Преглед изворни кода

Merge branch 'uat-20260202' of http://8.152.195.41:3000/alien/alien_cloud into uat-20260202

dujian пре 1 месец
родитељ
комит
3d3aa76b76

+ 6 - 4
alien-dining/src/main/java/shop/alien/dining/controller/PaymentController.java

@@ -44,13 +44,15 @@ public class PaymentController {
             @ApiImplicitParam(name = "payType", value = "支付类型(alipay:支付宝, wechatPay:微信支付)", required = true, paramType = "query", dataType = "String"),
             @ApiImplicitParam(name = "payer", value = "支付用户", required = true, paramType = "query", dataType = "String"),
             @ApiImplicitParam(name = "orderNo", value = "订单号", required = true, paramType = "query", dataType = "String"),
-            @ApiImplicitParam(name = "storeId", value = "店铺ID,用于从 MySQL 获取该店铺支付配置(StorePaymentConfig)", required = true, paramType = "query", dataType = "Integer")
+            @ApiImplicitParam(name = "storeId", value = "店铺ID,用于从 MySQL 获取该店铺支付配置(StorePaymentConfig)", required = true, paramType = "query", dataType = "Integer"),
+            @ApiImplicitParam(name ="couponId", value = "优惠券Id"),
+            @ApiImplicitParam(name = "payerId", value = "payerId")
     })
     @RequestMapping("/prePay")
-    public R prePay(String price, String subject, String payType, String payer, String orderNo, Integer storeId) {
-        log.info("PaymentController:prePay, price: {}, subject: {}, payType: {}, payer: {}, orderNo: {}, storeId: {}", price, subject, payType, payer, orderNo, storeId);
+    public R prePay(String price, String subject, String payType, String payer, String orderNo, Integer storeId,Integer couponId, Integer payerId) {
+        log.info("PaymentController:prePay, price: {}, subject: {}, payType: {}, payer: {}, orderNo: {}, storeId: {},couponId:{},payerId:{}", price, subject, payType, payer, orderNo, storeId,couponId,payerId);
         try {
-            return paymentStrategyFactory.getStrategy(payType).createPrePayOrder(price, subject, payer, orderNo, storeId);
+            return paymentStrategyFactory.getStrategy(payType).createPrePayOrder(price, subject, payer, orderNo, storeId, couponId,payerId);
         } catch (Exception e) {
             return R.fail(e.getMessage());
         }

+ 1 - 1
alien-dining/src/main/java/shop/alien/dining/strategy/payment/PaymentStrategy.java

@@ -23,7 +23,7 @@ public interface PaymentStrategy {
      * @return 预支付订单信息
      * @throws Exception 生成异常
      */
-    R createPrePayOrder(String price, String subject, String payer, String orderNo, Integer storeId) throws Exception;
+    R createPrePayOrder(String price, String subject, String payer, String orderNo, Integer storeId, Integer couponId, Integer payerId) throws Exception;
 
 
     /**

+ 67 - 2
alien-dining/src/main/java/shop/alien/dining/strategy/payment/impl/WeChatPaymentMininProgramStrategyImpl.java

@@ -23,9 +23,12 @@ import shop.alien.dining.strategy.payment.PaymentStrategy;
 import shop.alien.dining.util.WXPayUtility;
 import shop.alien.dining.util.WeChatPayUtil;
 import shop.alien.entity.result.R;
+import shop.alien.entity.store.LifeDiscountCouponUser;
 import shop.alien.entity.store.StoreOrder;
 import shop.alien.entity.store.StorePaymentConfig;
+import shop.alien.mapper.LifeDiscountCouponUserMapper;
 import shop.alien.mapper.StorePaymentConfigMapper;
+import shop.alien.util.common.constant.DiscountCouponEnum;
 import shop.alien.util.common.constant.PaymentEnum;
 
 import javax.servlet.http.HttpServletRequest;
@@ -36,6 +39,7 @@ import java.security.PrivateKey;
 import java.security.PublicKey;
 import java.security.Signature;
 import java.util.Base64;
+import java.util.Date;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -85,6 +89,7 @@ public class WeChatPaymentMininProgramStrategyImpl implements PaymentStrategy {
 
     private final StoreOrderService storeOrderService;
     private final StorePaymentConfigMapper storePaymentConfigMapper;
+    private final LifeDiscountCouponUserMapper lifeDiscountCouponUserMapper;
     private final ObjectMapper objectMapper;
 
     private static String POSTMETHOD = "POST";
@@ -153,7 +158,7 @@ public class WeChatPaymentMininProgramStrategyImpl implements PaymentStrategy {
     }
 
     @Override
-    public R createPrePayOrder(String price, String subject, String payer, String orderNo, Integer storeId) throws Exception {
+    public R createPrePayOrder(String price, String subject, String payer, String orderNo, Integer storeId, Integer couponId, Integer payerId) throws Exception {
         // 本系统调用:通过 storeId 从 MySQL 获取店铺支付配置
         if (storeId == null) {
             log.warn("createPrePayOrder 缺少 storeId,无法获取支付配置");
@@ -181,12 +186,52 @@ public class WeChatPaymentMininProgramStrategyImpl implements PaymentStrategy {
         request.appid = appId;
         request.mchid = mchId;
         request.description = subject;
-        request.outTradeNo = orderNo;
         request.notifyUrl = prePayNotifyUrl;
         request.amount = new CommonAmountInfo();
         request.amount.total = Long.parseLong(price);
         request.payer = new JsapiReqPayerInfo();
         request.payer.openid = payer;
+
+        String wechatOutTradeNo = orderNo;
+        StoreOrder storeOrder = storeOrderService.getOrderByOrderNo(orderNo);
+        if (storeOrder != null && StringUtils.hasText(storeOrder.getPayTradeNo())) {
+            if (storeOrder.getPayStatus() != null && storeOrder.getPayStatus() == 1) {
+                return R.fail("订单已支付");
+            }
+            PublicKey publicKey = loadPublicKeyFromConfig(config);
+            if (publicKey == null) {
+                return R.fail("店铺微信支付公钥未配置或加载失败");
+            }
+            QueryByWxTradeNoRequest q = new QueryByWxTradeNoRequest();
+            q.transactionId = storeOrder.getPayTradeNo();
+            q.mchid = mchId;
+            try {
+                DirectAPIv3QueryResponse wxOrder = searchOrderRun(q, config, privateKey, publicKey);
+                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("预支付前查询微信订单失败 out_trade_no={}, status={}, code={}, msg={}",
+                            storeOrder.getPayTradeNo(), e.getStatusCode(), 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("未支付场景已换新微信商户单号 orderNo={}, payTradeNo={}", orderNo, newPayTradeNo);
+        }
+        if (storeOrder != null) {
+            storeOrder.setCouponId(couponId);
+            storeOrder.setPayUserId(payerId);
+            if (!storeOrderService.updateById(storeOrder)) {
+                log.error("更新订单失败 orderNo={}", orderNo);
+                return R.fail("更新订单失败");
+            }
+        }
+        request.outTradeNo = wechatOutTradeNo;
+
         try {
             DirectAPIv3JsapiPrepayResponse response = doCreatePrePayOrder(request, config, privateKey);
             log.info("微信预支付订单创建成功,预支付ID:{}", response.prepayId);
@@ -296,11 +341,31 @@ public class WeChatPaymentMininProgramStrategyImpl implements PaymentStrategy {
             if ("SUCCESS".equals(tradeState)) {
                 String outTradeNo = jsonObject.getString("out_trade_no");
                 StoreOrder storeOrder = storeOrderService.getOne(new QueryWrapper<StoreOrder>().eq("order_no", outTradeNo));
+                if (storeOrder == null && StringUtils.hasText(outTradeNo)) {
+                    storeOrder = storeOrderService.getOne(new QueryWrapper<StoreOrder>().eq("pay_trade_no", outTradeNo));
+                }
                 if (storeOrder != null && storeOrder.getPayStatus() != 1) {
                     storeOrder.setPayStatus(1);
                     storeOrder.setOrderStatus(1);
                     if (storeOrderService.updateById(storeOrder)) {
                         log.info("小程序更新订单成功,订单号outTradeNo:{}", outTradeNo);
+                        if (storeOrder.getCouponId() != null && storeOrder.getPayUserId() != null) {
+                            LambdaQueryWrapper<LifeDiscountCouponUser> couponUserWrapper = new LambdaQueryWrapper<>();
+                            couponUserWrapper.eq(LifeDiscountCouponUser::getUserId, storeOrder.getPayUserId());
+                            couponUserWrapper.eq(LifeDiscountCouponUser::getCouponId, storeOrder.getCouponId());
+                            couponUserWrapper.eq(LifeDiscountCouponUser::getStatus,
+                                    Integer.parseInt(DiscountCouponEnum.WAITING_USED.getValue()));
+                            couponUserWrapper.eq(LifeDiscountCouponUser::getDeleteFlag, 0);
+                            couponUserWrapper.orderByDesc(LifeDiscountCouponUser::getCreatedTime);
+                            couponUserWrapper.last("LIMIT 1");
+                            LifeDiscountCouponUser couponUser = lifeDiscountCouponUserMapper.selectOne(couponUserWrapper);
+                            if (couponUser != null) {
+                                couponUser.setStatus(Integer.parseInt(DiscountCouponEnum.HAVE_BEEN_USED.getValue()));
+                                couponUser.setUseTime(new Date());
+                                lifeDiscountCouponUserMapper.updateById(couponUser);
+                                log.info("支付成功,已更新 life_discount_coupon_user 为已使用, id={}", couponUser.getId());
+                            }
+                        }
                         // 支付完成后,清空购物车和重置餐桌状态(保留订单数据,不删除订单)
                         try {
                             storeOrderService.resetTableAfterPayment(storeOrder.getTableId());

+ 2 - 0
alien-store/src/main/java/shop/alien/store/controller/OSSDirectUploadNewController.java

@@ -12,6 +12,7 @@ import org.apache.commons.codec.binary.Base64;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.cloud.context.config.annotation.RefreshScope;
 import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.CrossOrigin;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
@@ -38,6 +39,7 @@ import java.util.*;
 @RestController
 @RequestMapping("/oss/direct/new")
 @RefreshScope
+@CrossOrigin
 public class OSSDirectUploadNewController {
 
     @Value("${ali.oss.accessKeyId}")