|
|
@@ -1,5 +1,7 @@
|
|
|
package shop.alien.store.strategy.payment.impl;
|
|
|
|
|
|
+import com.alibaba.fastjson.JSONObject;
|
|
|
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
import com.google.gson.annotations.SerializedName;
|
|
|
import lombok.RequiredArgsConstructor;
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
@@ -9,16 +11,25 @@ import org.springframework.beans.factory.annotation.Value;
|
|
|
import org.springframework.stereotype.Component;
|
|
|
import shop.alien.entity.result.R;
|
|
|
import shop.alien.entity.store.StoreInfo;
|
|
|
+import shop.alien.entity.store.StoreOrder;
|
|
|
+import shop.alien.entity.store.StorePaymentConfig;
|
|
|
+import shop.alien.entity.store.LifeDiscountCouponUser;
|
|
|
import shop.alien.entity.store.RefundRecord;
|
|
|
+import shop.alien.mapper.LifeDiscountCouponUserMapper;
|
|
|
import shop.alien.mapper.StoreInfoMapper;
|
|
|
+import shop.alien.mapper.StoreOrderMapper;
|
|
|
+import shop.alien.store.feign.DiningServiceFeign;
|
|
|
import shop.alien.store.service.RefundRecordService;
|
|
|
+import shop.alien.store.service.StorePaymentConfigService;
|
|
|
import shop.alien.store.strategy.payment.PaymentStrategy;
|
|
|
import shop.alien.store.util.WXPayUtility;
|
|
|
import shop.alien.util.common.UniqueRandomNumGenerator;
|
|
|
+import shop.alien.util.common.constant.DiscountCouponEnum;
|
|
|
import shop.alien.util.common.constant.PaymentEnum;
|
|
|
import shop.alien.util.system.OSUtil;
|
|
|
|
|
|
import javax.annotation.PostConstruct;
|
|
|
+import javax.servlet.http.HttpServletRequest;
|
|
|
import java.io.IOException;
|
|
|
import java.io.UncheckedIOException;
|
|
|
import java.math.BigDecimal;
|
|
|
@@ -27,8 +38,11 @@ import java.security.PrivateKey;
|
|
|
import java.security.PublicKey;
|
|
|
import java.security.Signature;
|
|
|
import java.util.Base64;
|
|
|
+import java.util.Date;
|
|
|
+import java.util.Enumeration;
|
|
|
import java.util.HashMap;
|
|
|
import java.util.Map;
|
|
|
+import java.util.concurrent.CompletableFuture;
|
|
|
|
|
|
/**
|
|
|
* 微信支付 — 服务商模式(特约商户 / partner)
|
|
|
@@ -55,6 +69,14 @@ public class WeChatPartnerPaymentStrategyImpl implements PaymentStrategy {
|
|
|
private final RefundRecordService refundRecordService;
|
|
|
/** 按门店读取 store_info.wechat_sub_mchid(特约商户号),与前端传入的 storeId 对应 */
|
|
|
private final StoreInfoMapper storeInfoMapper;
|
|
|
+ /** 预下单时按业务订单号更新 store_order */
|
|
|
+ private final StoreOrderMapper storeOrderMapper;
|
|
|
+ /** 按门店解析子商户 AppID(sub_appid),与小程序策略一致 */
|
|
|
+ private final StorePaymentConfigService storePaymentConfigService;
|
|
|
+ /** 支付成功回调:核销优惠券(与小程序服务商策略一致) */
|
|
|
+ private final LifeDiscountCouponUserMapper lifeDiscountCouponUserMapper;
|
|
|
+ /** 支付成功回调:重置餐桌/购物车逻辑在 alien-dining,通过 Feign 调用 */
|
|
|
+ private final DiningServiceFeign diningServiceFeign;
|
|
|
/** 复用直连实现中的退款单模型、HTTP 工具与 RefundRecord 构建逻辑(构建后覆盖 payType 为服务商类型) */
|
|
|
private final WeChatPaymentStrategyImpl weChatPaymentStrategy;
|
|
|
|
|
|
@@ -121,6 +143,10 @@ public class WeChatPartnerPaymentStrategyImpl implements PaymentStrategy {
|
|
|
@Value("${payment.wechatPartnerPay.business.refundNotifyUrl}")
|
|
|
private String refundNotifyUrl;
|
|
|
|
|
|
+ /** 支付结果通知 resource 解密(与小程序服务商策略一致,回调验签通过后解密) */
|
|
|
+ @Value("${payment.wechatPartnerPay.business.apiV3Key:}")
|
|
|
+ private String apiV3Key;
|
|
|
+
|
|
|
private PrivateKey privateKey;
|
|
|
private PublicKey wechatPayPublicKey;
|
|
|
|
|
|
@@ -145,14 +171,28 @@ public class WeChatPartnerPaymentStrategyImpl implements PaymentStrategy {
|
|
|
|
|
|
@Override
|
|
|
public R createPrePayOrder(String price, String subject) throws Exception {
|
|
|
- return createPrePayOrder(price, subject, null);
|
|
|
+ return createPrePayOrder(price, subject, null, null, null, null, null, null, null, null);
|
|
|
}
|
|
|
|
|
|
@Override
|
|
|
public R createPrePayOrder(String price, String subject, Integer storeId) throws Exception {
|
|
|
+ return createPrePayOrder(price, subject, null, null, storeId, null, null, null, null, null);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 与 {}
|
|
|
+ * 参数对齐:有 orderNo 时刷新 {@link StoreOrder} 的 pay_trade_no 及费用字段,商户单号与微信 out_trade_no 一致。
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public R createPrePayOrder(String price, String subject, String payer, String orderNo, Integer storeId,
|
|
|
+ Integer couponId, Integer payerId, String serviceFee, String discountAmount,
|
|
|
+ String payAmount) throws Exception {
|
|
|
String subMchid = resolveSubMchidFromStore(storeId);
|
|
|
- log.info("[WeChatPartner] 创建预支付订单,price={}, subject={}, spMchId={}, storeId={}, subMchid={}",
|
|
|
- price, subject, spMchId, storeId, subMchid != null ? subMchid : "(未解析)");
|
|
|
+ log.info("[WeChatPartner] 创建预支付订单,price={}, subject={}, spMchId={}, storeId={}, orderNo={}, subMchid={}",
|
|
|
+ price, subject, spMchId, storeId, orderNo, subMchid != null ? subMchid : "(未解析)");
|
|
|
+ // 与小程序策略入参一致;服务商 APP 下单无需 sp_openid,仅记录便于与前端联调对照
|
|
|
+ log.debug("[WeChatPartner] 扩展参数 payer(APP 不使用)={}, couponId={}, payerId={}, serviceFee={}, discountAmount={}, payAmount={}",
|
|
|
+ payer, couponId, payerId, serviceFee, discountAmount, payAmount);
|
|
|
if (subMchid == null) {
|
|
|
return R.fail("请传入门店 storeId,且门店需在 store_info 中维护微信特约商户号 wechat_sub_mchid");
|
|
|
}
|
|
|
@@ -171,15 +211,58 @@ public class WeChatPartnerPaymentStrategyImpl implements PaymentStrategy {
|
|
|
return R.fail("价格格式不正确");
|
|
|
}
|
|
|
|
|
|
+ String wechatOutTradeNo;
|
|
|
+ if (StringUtils.isNotBlank(orderNo)) {
|
|
|
+ wechatOutTradeNo = orderNo.trim();
|
|
|
+ LambdaQueryWrapper<StoreOrder> ow = new LambdaQueryWrapper<>();
|
|
|
+ ow.eq(StoreOrder::getOrderNo, wechatOutTradeNo);
|
|
|
+ ow.eq(StoreOrder::getDeleteFlag, 0);
|
|
|
+ StoreOrder storeOrder = storeOrderMapper.selectOne(ow);
|
|
|
+ log.info("[WeChatPartner] createPrePayOrder orderNo={}, storeOrderFound={}, subMchid={}", orderNo, storeOrder != null, subMchid);
|
|
|
+
|
|
|
+ if (storeOrder != null) {
|
|
|
+ if (storeOrder.getPayStatus() != null && storeOrder.getPayStatus() == 1) {
|
|
|
+ return R.fail("订单已支付");
|
|
|
+ }
|
|
|
+ if (storeOrder.getPayTradeNo() != null) {
|
|
|
+ try {
|
|
|
+ WeChatPaymentStrategyImpl.DirectAPIv3QueryResponse wxOrder =
|
|
|
+ partnerSearchOrderRun(storeOrder.getPayTradeNo(), subMchid);
|
|
|
+ if (wxOrder != null && "SUCCESS".equals(wxOrder.tradeState)) {
|
|
|
+ return R.fail("该支付单已在微信侧支付成功,请勿重复发起支付");
|
|
|
+ }
|
|
|
+ } catch (WXPayUtility.ApiException e) {
|
|
|
+ if (e.getStatusCode() != 404 && !"ORDER_NOT_EXIST".equals(e.getErrorCode())) {
|
|
|
+ log.error("[WeChatPartner] 预支付前查单失败 payTradeNo={}, code={}, msg={}",
|
|
|
+ storeOrder.getPayTradeNo(), e.getErrorCode(), e.getErrorMessage());
|
|
|
+ return R.fail("查询微信支付订单失败:" + (e.getErrorMessage() != null ? e.getErrorMessage() : e.getMessage()));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ String newPayTradeNo = "WX" + storeOrder.getId() + "_" + System.currentTimeMillis();
|
|
|
+ storeOrder.setPayTradeNo(newPayTradeNo);
|
|
|
+ wechatOutTradeNo = newPayTradeNo;
|
|
|
+ log.info("[WeChatPartner] 换新商户单号 orderNo={}, payTradeNo={}", orderNo, newPayTradeNo);
|
|
|
+ storeOrder.setCouponId(couponId);
|
|
|
+ storeOrder.setPayUserId(payerId);
|
|
|
+ storeOrder.setServiceFee(parseAmountOrZero(serviceFee));
|
|
|
+ storeOrder.setDiscountAmount(parseAmountOrZero(discountAmount));
|
|
|
+ storeOrder.setPayAmount(parseAmountOrZero(payAmount));
|
|
|
+ if (storeOrderMapper.updateById(storeOrder) <= 0) {
|
|
|
+ log.error("[WeChatPartner] 更新订单失败 orderNo={}", orderNo);
|
|
|
+ return R.fail("更新订单失败");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ wechatOutTradeNo = UniqueRandomNumGenerator.generateUniqueCode(19);
|
|
|
+ }
|
|
|
+
|
|
|
PartnerAppPrepayRequest request = new PartnerAppPrepayRequest();
|
|
|
request.spAppid = spAppId;
|
|
|
request.spMchid = spMchId;
|
|
|
request.subMchid = subMchid;
|
|
|
- if (StringUtils.isNotBlank(subAppId)) {
|
|
|
- request.subAppid = subAppId;
|
|
|
- }
|
|
|
request.description = subject;
|
|
|
- request.outTradeNo = UniqueRandomNumGenerator.generateUniqueCode(19);
|
|
|
+ request.outTradeNo = wechatOutTradeNo;
|
|
|
request.notifyUrl = prePayNotifyUrl;
|
|
|
request.amount = new WeChatPaymentStrategyImpl.CommonAmountInfo();
|
|
|
request.amount.total = new BigDecimal(price).multiply(new BigDecimal(100)).longValue();
|
|
|
@@ -189,12 +272,10 @@ public class WeChatPartnerPaymentStrategyImpl implements PaymentStrategy {
|
|
|
WeChatPaymentStrategyImpl.DirectAPIv3AppPrepayResponse response = partnerPrePayOrderRun(request);
|
|
|
log.info("[WeChatPartner] 预下单成功 prepayId={}, outTradeNo={}", response.prepayId, request.outTradeNo);
|
|
|
|
|
|
- String clientAppId = StringUtils.isNotBlank(subAppId) ? subAppId : spAppId;
|
|
|
Map<String, String> result = new HashMap<>();
|
|
|
result.put("prepayId", response.prepayId);
|
|
|
- result.put("appId", clientAppId);
|
|
|
+ result.put("appId", spAppId);
|
|
|
result.put("spAppId", spAppId);
|
|
|
- result.put("subAppId", subAppId);
|
|
|
result.put("spMchId", spMchId);
|
|
|
result.put("subMchId", subMchid);
|
|
|
result.put("orderNo", request.outTradeNo);
|
|
|
@@ -202,7 +283,7 @@ public class WeChatPartnerPaymentStrategyImpl implements PaymentStrategy {
|
|
|
long timestamp = System.currentTimeMillis() / 1000;
|
|
|
String nonce = WXPayUtility.createNonce(32);
|
|
|
String prepayId = response.prepayId;
|
|
|
- String message = String.format("%s\n%s\n%s\n%s\n", clientAppId, timestamp, nonce, prepayId);
|
|
|
+ String message = String.format("%s\n%s\n%s\n", timestamp, nonce, prepayId);
|
|
|
Signature sign = Signature.getInstance("SHA256withRSA");
|
|
|
sign.initSign(privateKey);
|
|
|
sign.update(message.getBytes(StandardCharsets.UTF_8));
|
|
|
@@ -216,9 +297,186 @@ public class WeChatPartnerPaymentStrategyImpl implements PaymentStrategy {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 子商户 AppID:门店支付配置优先,否则使用全局 {@code payment.wechatPartnerPay.business.subAppId}。
|
|
|
+ */
|
|
|
+ private String resolveSubAppId(StorePaymentConfig config) {
|
|
|
+ if (config != null) {
|
|
|
+ if (org.springframework.util.StringUtils.hasText(config.getWechatMiniAppId())) {
|
|
|
+ return config.getWechatMiniAppId().trim();
|
|
|
+ }
|
|
|
+ if (org.springframework.util.StringUtils.hasText(config.getWechatAppId())) {
|
|
|
+ return config.getWechatAppId().trim();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (StringUtils.isNotBlank(subAppId)) {
|
|
|
+ return subAppId.trim();
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ /** 解析金额字符串,空或非法时记日志并返回 0,避免更新订单时 NPE */
|
|
|
+ private static BigDecimal parseAmountOrZero(String raw) {
|
|
|
+ if (raw == null || raw.trim().isEmpty()) {
|
|
|
+ return BigDecimal.ZERO;
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ return new BigDecimal(raw.trim());
|
|
|
+ } catch (NumberFormatException e) {
|
|
|
+ return BigDecimal.ZERO;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
@Override
|
|
|
public R handleNotify(String notifyData) throws Exception {
|
|
|
- return null;
|
|
|
+ log.warn("[WeChatPartner回调] 缺少 HttpServletRequest,无法进行 APIv3 验签,请使用 POST /payment/weChatPartnerNotify");
|
|
|
+ return R.fail("请使用微信支付回调专用接口(需携带 Wechatpay-* 请求头)");
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 与 {} 对齐:
|
|
|
+ * 验签、解密 resource,异步更新订单/优惠券,并通过 Feign 调用 dining 重置餐桌。
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public R handleNotify(String notifyData, HttpServletRequest request) throws Exception {
|
|
|
+ log.info("[WeChatPartner回调] 进入 handleNotify, len={}", notifyData != null ? notifyData.length() : 0);
|
|
|
+ if (request == null) {
|
|
|
+ return R.fail("请求上下文缺失");
|
|
|
+ }
|
|
|
+ String serial = request.getHeader("Wechatpay-Serial");
|
|
|
+ String signature = request.getHeader("Wechatpay-Signature");
|
|
|
+ String timestamp = request.getHeader("Wechatpay-Timestamp");
|
|
|
+ String nonce = request.getHeader("Wechatpay-Nonce");
|
|
|
+
|
|
|
+ if (serial == null || signature == null || timestamp == null || nonce == null) {
|
|
|
+ log.warn("[WeChatPartner回调] 验签参数缺失 serial={}, signature={}, timestamp={}, nonce={}",
|
|
|
+ serial, signature != null, timestamp, nonce);
|
|
|
+ return R.fail("验签参数缺失");
|
|
|
+ }
|
|
|
+
|
|
|
+ if (signature.startsWith("WECHATPAY/SIGNTEST/")) {
|
|
|
+ log.info("[WeChatPartner回调] 签名探测请求,直接成功");
|
|
|
+ return R.success("OK");
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!StringUtils.equals(serial, wechatPayPublicKeyId)) {
|
|
|
+ log.warn("[WeChatPartner回调] Wechatpay-Serial 与配置不符 serial={}, expected={}", serial, wechatPayPublicKeyId);
|
|
|
+ return R.fail("公钥序列号不匹配");
|
|
|
+ }
|
|
|
+ if (wechatPayPublicKey == null) {
|
|
|
+ log.error("[WeChatPartner回调] 平台公钥未加载");
|
|
|
+ return R.fail("平台公钥未就绪");
|
|
|
+ }
|
|
|
+
|
|
|
+ Headers okHeaders = buildOkHttpHeaders(request);
|
|
|
+
|
|
|
+ if (!org.springframework.util.StringUtils.hasText(apiV3Key)) {
|
|
|
+ log.error("[WeChatPartner回调] 未配置 payment.wechatPartnerPay.business.apiV3Key,无法解密");
|
|
|
+ return R.fail("APIv3 密钥未配置");
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ WXPayUtility.Notification parsed = WXPayUtility.parseNotification(apiV3Key, wechatPayPublicKeyId,
|
|
|
+ wechatPayPublicKey, okHeaders, notifyData);
|
|
|
+ String plaintext = parsed.getPlaintext();
|
|
|
+ if (plaintext == null || plaintext.isEmpty()) {
|
|
|
+ log.warn("[WeChatPartner回调] 解密后业务数据为空");
|
|
|
+ return R.fail("解密结果为空");
|
|
|
+ }
|
|
|
+ final String plainCopy = plaintext;
|
|
|
+ CompletableFuture.runAsync(() -> processPartnerNotifyBusiness(plainCopy));
|
|
|
+ return R.success("OK");
|
|
|
+ } catch (IllegalArgumentException e) {
|
|
|
+ log.error("[WeChatPartner回调] 验签或解密失败: {}", e.getMessage());
|
|
|
+ return R.fail(e.getMessage() != null ? e.getMessage() : "处理失败");
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("[WeChatPartner回调] 处理异常", e);
|
|
|
+ return R.fail(e.getMessage() != null ? e.getMessage() : "处理异常");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private static Headers buildOkHttpHeaders(HttpServletRequest request) {
|
|
|
+ Headers.Builder b = new Headers.Builder();
|
|
|
+ Enumeration<String> names = request.getHeaderNames();
|
|
|
+ while (names != null && names.hasMoreElements()) {
|
|
|
+ String name = names.nextElement();
|
|
|
+ Enumeration<String> values = request.getHeaders(name);
|
|
|
+ while (values != null && values.hasMoreElements()) {
|
|
|
+ b.add(name, values.nextElement());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return b.build();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 异步:解析支付成功报文,更新 store_order、优惠券,并通知 dining 重置餐桌(与小程序服务商回调业务一致)
|
|
|
+ */
|
|
|
+ private void processPartnerNotifyBusiness(String plaintext) {
|
|
|
+ try {
|
|
|
+ JSONObject jsonObject = JSONObject.parseObject(plaintext);
|
|
|
+ String tradeState = jsonObject.getString("trade_state");
|
|
|
+ if (!"SUCCESS".equals(tradeState)) {
|
|
|
+ log.info("[WeChatPartner回调] trade_state 非 SUCCESS: {}", tradeState);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ String outTradeNo = jsonObject.getString("out_trade_no");
|
|
|
+ if (outTradeNo == null || outTradeNo.isEmpty()) {
|
|
|
+ log.warn("[WeChatPartner回调] 缺少 out_trade_no");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ LambdaQueryWrapper<StoreOrder> byOrderNo = new LambdaQueryWrapper<>();
|
|
|
+ byOrderNo.eq(StoreOrder::getOrderNo, outTradeNo).eq(StoreOrder::getDeleteFlag, 0);
|
|
|
+ StoreOrder storeOrder = storeOrderMapper.selectOne(byOrderNo);
|
|
|
+ if (storeOrder == null) {
|
|
|
+ LambdaQueryWrapper<StoreOrder> byPayTrade = new LambdaQueryWrapper<>();
|
|
|
+ byPayTrade.eq(StoreOrder::getPayTradeNo, outTradeNo).eq(StoreOrder::getDeleteFlag, 0);
|
|
|
+ storeOrder = storeOrderMapper.selectOne(byPayTrade);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (storeOrder != null && !Integer.valueOf(1).equals(storeOrder.getPayStatus())) {
|
|
|
+ storeOrder.setPayStatus(1);
|
|
|
+ storeOrder.setOrderStatus(1);
|
|
|
+ storeOrder.setPayType(1);
|
|
|
+ storeOrder.setPayTime(new Date());
|
|
|
+ int rows = storeOrderMapper.updateById(storeOrder);
|
|
|
+ if (rows > 0) {
|
|
|
+ log.info("[WeChatPartner回调] 更新订单支付成功 outTradeNo={}", outTradeNo);
|
|
|
+ if (storeOrder.getCouponId() != null && storeOrder.getPayUserId() != null) {
|
|
|
+ LambdaQueryWrapper<LifeDiscountCouponUser> cw = new LambdaQueryWrapper<>();
|
|
|
+ cw.eq(LifeDiscountCouponUser::getUserId, storeOrder.getPayUserId());
|
|
|
+ cw.eq(LifeDiscountCouponUser::getCouponId, storeOrder.getCouponId());
|
|
|
+ cw.eq(LifeDiscountCouponUser::getStatus, Integer.parseInt(DiscountCouponEnum.WAITING_USED.getValue()));
|
|
|
+ cw.eq(LifeDiscountCouponUser::getDeleteFlag, 0);
|
|
|
+ cw.orderByDesc(LifeDiscountCouponUser::getCreatedTime);
|
|
|
+ cw.last("LIMIT 1");
|
|
|
+ LifeDiscountCouponUser couponUser = lifeDiscountCouponUserMapper.selectOne(cw);
|
|
|
+ if (couponUser != null) {
|
|
|
+ couponUser.setStatus(Integer.parseInt(DiscountCouponEnum.HAVE_BEEN_USED.getValue()));
|
|
|
+ couponUser.setUseTime(new Date());
|
|
|
+ lifeDiscountCouponUserMapper.updateById(couponUser);
|
|
|
+ log.info("[WeChatPartner回调] 优惠券已使用 id={}", couponUser.getId());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ try {
|
|
|
+ R<Void> feignRet =
|
|
|
+ diningServiceFeign.resetTableAfterPaymentInternal(storeOrder.getTableId(), storeOrder.getMenuType());
|
|
|
+ if (!R.isSuccess(feignRet)) {
|
|
|
+ log.error("[WeChatPartner回调] Feign 重置餐桌失败 tableId={}, msg={}",
|
|
|
+ storeOrder.getTableId(), feignRet != null ? feignRet.getMsg() : "null");
|
|
|
+ } else {
|
|
|
+ log.info("[WeChatPartner回调] 已请求 dining 重置餐桌 tableId={}", storeOrder.getTableId());
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("[WeChatPartner回调] Feign 重置餐桌异常 tableId={}", storeOrder.getTableId(), e);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ log.warn("[WeChatPartner回调] 更新订单影响行数为 0, orderId={}", storeOrder.getId());
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("[WeChatPartner回调] 异步处理异常", e);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
@Override
|