From 3f45e8fdfa31d7b764d60a7c0cb5dd11944ed418 Mon Sep 17 00:00:00 2001
From: 刘帅 <rr.iii@qq.com>
Date: 星期一, 21 九月 2026 23:38:59 +0800
Subject: [PATCH] bug:统计数据修正

---
 cloud-server-account/src/main/java/com/dsh/account/service/impl/TAppUserServiceImpl.java |  315 +++++++++++++++++++++++++++++++++++++++++++++------
 1 files changed, 275 insertions(+), 40 deletions(-)

diff --git a/cloud-server-account/src/main/java/com/dsh/account/service/impl/TAppUserServiceImpl.java b/cloud-server-account/src/main/java/com/dsh/account/service/impl/TAppUserServiceImpl.java
index 1ab1194..f33edaf 100644
--- a/cloud-server-account/src/main/java/com/dsh/account/service/impl/TAppUserServiceImpl.java
+++ b/cloud-server-account/src/main/java/com/dsh/account/service/impl/TAppUserServiceImpl.java
@@ -12,8 +12,11 @@
 import com.alipay.api.response.AlipayTradeOrderSettleResponse;
 import com.alipay.api.response.AlipayTradeQueryResponse;
 import com.alipay.api.response.AlipayTradeRoyaltyRelationBindResponse;
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.dsh.account.dto.*;
 import com.dsh.account.entity.*;
@@ -42,10 +45,7 @@
 import com.dsh.account.model.vo.classDetails.RegisteredCourse;
 import com.dsh.account.model.vo.classDetails.classInsVo.ClassInfoVo;
 import com.dsh.account.model.vo.userBenefitDetail.*;
-import com.dsh.account.service.IRefereeService;
-import com.dsh.account.service.TAppGiftService;
-import com.dsh.account.service.TAppUserService;
-import com.dsh.account.service.UserIntegralChangesService;
+import com.dsh.account.service.*;
 import com.dsh.account.util.*;
 import com.dsh.account.util.akeylogin.Md5Util;
 import com.dsh.account.util.wx.WxV3PayConfig;
@@ -56,6 +56,7 @@
 import com.dsh.account.vo.entity.YearData;
 import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.data.domain.Page;
 import org.springframework.data.domain.PageImpl;
 import org.springframework.data.domain.PageRequest;
@@ -86,6 +87,10 @@
 @Service
 public class TAppUserServiceImpl extends ServiceImpl<TAppUserMapper, TAppUser> implements TAppUserService {
 
+    private static final String SMS_COOLDOWN_KEY_PREFIX = "security:sms:cooldown:";
+    private static final String SMS_PHONE_QUOTA_KEY_PREFIX = "security:sms:phone-quota:";
+    private static final String SMS_IP_QUOTA_KEY_PREFIX = "security:sms:ip-quota:";
+
 
     @Resource
     private TStudentMapper tsmapper;
@@ -98,6 +103,15 @@
 
     @Autowired
     private RedisUtil redisUtil;
+
+    @Value("${security.sms.cooldown-seconds:60}")
+    private int smsCooldownSeconds;
+
+    @Value("${security.sms.phone-max-per-day:5}")
+    private int smsPhoneMaxPerDay;
+
+    @Value("${security.sms.ip-max-per-day:10}")
+    private int smsIpMaxPerDay;
 
     @Autowired
     private GDMapGeocodingUtil gdMapGeocodingUtil;
@@ -153,6 +167,8 @@
 
     @Resource
     private TAppUserMapper appUserMapper;
+    @Autowired
+    private UserAuditService userAuditService;
 
     @Autowired
     private TAppGiftService appGiftService;
@@ -162,6 +178,8 @@
 
 
     private String aliAppid = "2021004105665036";//支付宝appid
+    // 默认头像
+    private String headImg = "https://we-park-life.oss-cn-beijing.aliyuncs.com/img/f7fbeaed277a45ab9591b70dc5699cab.jpg";
 
     private String appPrivateKey = "MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCi5i9nW/hGLJ3A06cZxTQdviFC7THpdSihoTYGLr9q006hu0V26ecBMY/o4w5bvIX0Ok/yofmZsVcCJpAPvbXL/uqVrIjnRRxXiaeBFThlxoBUTdunvbUSDYfzlEhJr5NvUKI6H6lz2niXlQGx4qy8Hau4ccWit9kM8jwUvsBVQoFgJA+xrjMvooA7YLopQtpOD+UJr5thApTSf1xrnr1W12yolTLEH15JmNV372cqXrYUuqnY0QsaPtxeqJUGAOcGdVLllQ7easEznP8DFBvDdHATcmp2SHNQDUEWN6MCVPbMgY06NQVqAXxqjTAYSVh+6TRu6bofPmpYC3TZB003AgMBAAECggEBAJAcR2+PA3NBYUYHeFrqBRMS8uX8ZR19kjZ7IgoSLTFaQsP9opRylPSPXhrPVBKAE5leRQAHn4MCSlESwHvMfxo7KFjFTFAc6dffZZpipYQUOc9bGampwJh58/3e/pyBgVMG6J23CPf/HJQtNFSkjd/V9+ayb/9l2dUEL3bC0fAZ/dbx8HsxdLw8wn3fLlWLj68hOMqa2deCZe3JdSVsPbeWqkh56FFsMLug0Nd+Ar4TgRl9/jnhXF0JWiD0LmPUYLhboY7EfUBzN4w1iYbDi1P+3zvoOYsiVKAXox9GMhQ2VzOO2UcSTuizSza2e98mGpabl/GpKmCz+RDFjtkX6eECgYEA2MyCij65eO3aGIm3FUe93DULRBYTfX8qJQSJq2WOWA3mmQlEW6L3O2B5/lG2h+8WmN6iLEs9eHpgycGYp7vAqgrANEn16ACVcuyx0scFtrZfZ+kmHMzFfiUWxJjVYk/6YngsGVBLdw6ueM42C8TTP67X9tU5TdVGoGWuqEj4W98CgYEAwFqwprXOch5Pqk/RPbb49r0Ou03K/UbciWnWWKzUhFFNS8MdlQPoDvQZbMwHLeWsa2VhaKITK3x5biLQb3U+0GLOn6lTvEyrEUH+ucREyLgVYTRAvwBPtnvlrzpyxPk2HnslQjju8WrvvLLBMKWUjlTrTOzhaHT21gz3pHMiOakCgYEAhLmfaXdBITGshb054sNLDtdCkGpbgEcrzAHdLps769iGxkYQHXHFngpQZUwtTUcoNGqIKknd1jZFrv7gsD+XkgKG7PwimehRlkwmCX5ilxtLiVgJRzRt6+5U5AMVD90a0tHzXYP0z2yjj73fBJF5KtGl0a10KZxaYrQdm1UhB00CgYBZZgzx/k9rtHC8LAqIj1CYhHejT92G53c6Gkl3vyOqN4sgKhfGmSEySfrDGPRBPZxr8ZtbIPCd5mUdberH0osWGMYFaJI1UsCy7aQwvGpniz7MhZeN7dweaOjwDs8mgtjHQ96mL4XGCDhR0BZ/wIURvZ/6iaGdhbbu9unlsWj3uQKBgQCmZYdsbbZkd3ev6f8rwyvMz+DrCQyYpY44cegBYuJgrZiQnL2fJioeN7ixX0UM48SfwsZEIrzshP/LGAwnc2MdjxKUl4jLN8SEe0NAjXOnz9Zaw740+aOmLpXcLWdP4uM2gIhWsvW1tEkQZCXmm7c9s/RsU8Pmzv+YL3+fSijOzA==";//支付宝开发者应用私钥
 
@@ -413,13 +431,31 @@
      * @throws Exception
      */
     @Override
-    public ResultUtil getSMSCode(Integer type, String phone) throws Exception {
+    public ResultUtil getSMSCode(Integer type, String phone, String clientIp) throws Exception {
         if (type == 2) {
             TAppUser tAppUser = this.baseMapper.selectOne(new QueryWrapper<TAppUser>().eq("phone", phone).ne("state", 3));
             if (null != tAppUser) {
                 return ResultUtil.error("账号已存在");
             }
         }
+        String cooldownKey = SMS_COOLDOWN_KEY_PREFIX + phone;
+        if (!redisUtil.setIfAbsent(cooldownKey, "1", smsCooldownSeconds)) {
+            return ResultUtil.error("短信发送过于频繁,请稍后重试");
+        }
+
+        String phoneQuotaKey = SMS_PHONE_QUOTA_KEY_PREFIX + phone;
+        if (!redisUtil.tryAcquireFixedWindow(phoneQuotaKey, smsPhoneMaxPerDay, 24 * 60 * 60)) {
+            redisUtil.remove(cooldownKey);
+            return ResultUtil.error("该手机号24小时内短信发送次数已达上限");
+        }
+
+        String ipQuotaKey = SMS_IP_QUOTA_KEY_PREFIX + clientIp;
+        if (!redisUtil.tryAcquireFixedWindow(ipQuotaKey, smsIpMaxPerDay, 24 * 60 * 60)) {
+            redisUtil.remove(cooldownKey);
+            redisUtil.releaseFixedWindow(phoneQuotaKey);
+            return ResultUtil.error("当前网络24小时内短信发送次数已达上限");
+        }
+
         String numberRandom = UUIDUtil.getNumberRandom(6);
         String templateCode = "";
         if (type == 1 || type == 2) {
@@ -428,9 +464,29 @@
         if (type == 3 || type == 4) {
             templateCode = "SMS_160960014";
         }
-        aLiSendSms.sendSms(phone, templateCode, "{\"code\":\"" + numberRandom + "\"}");
-        redisUtil.setStrValue(phone, numberRandom, 300);
-        return ResultUtil.success();
+        boolean providerAccepted = false;
+        try {
+            String sendResult = aLiSendSms.sendSms(phone, templateCode, "{\"code\":\"" + numberRandom + "\"}");
+            com.alibaba.fastjson.JSONObject response = com.alibaba.fastjson.JSONObject.parseObject(sendResult);
+            if (response == null || !"OK".equalsIgnoreCase(response.getString("Code"))) {
+                releaseSmsLimit(cooldownKey, phoneQuotaKey, ipQuotaKey);
+                return ResultUtil.error("短信发送失败,请稍后重试");
+            }
+            providerAccepted = true;
+            redisUtil.setStrValue(phone, numberRandom, 300);
+            return ResultUtil.success();
+        } catch (Exception e) {
+            if (!providerAccepted) {
+                releaseSmsLimit(cooldownKey, phoneQuotaKey, ipQuotaKey);
+            }
+            throw e;
+        }
+    }
+
+    private void releaseSmsLimit(String cooldownKey, String phoneQuotaKey, String ipQuotaKey) {
+        redisUtil.remove(cooldownKey);
+        redisUtil.releaseFixedWindow(phoneQuotaKey);
+        redisUtil.releaseFixedWindow(ipQuotaKey);
     }
 
     /**
@@ -463,8 +519,12 @@
         tAppUser.setProvinceCode("");
         tAppUser.setCity("");
         tAppUser.setCityCode("");
+        tAppUser.setHeadImg(headImg);
         // 注册用户
         int insert = this.baseMapper.insert(tAppUser);
+        String s = generateNickname(tAppUser.getId());
+        tAppUser.setName(s);
+        this.baseMapper.updateById(tAppUser);
         // 介绍有礼
         if (addAppUserVo.getReferralUserId() != null || ToolUtil.isNotEmpty(addAppUserVo.getInvitePhone())) {
             if (ToolUtil.isEmpty(addAppUserVo.getLat()) || ToolUtil.isEmpty(addAppUserVo.getLon())) {
@@ -552,6 +612,7 @@
             return ResultUtil.error("验证码无效", "");
         }
         TAppUser tAppUser = this.baseMapper.selectOne(new QueryWrapper<TAppUser>().eq("phone", loginSMSCodeVo.getPhone()).ne("state", 3));
+//        System.out.println(tAppUser.getId()+"!!!!!!!!");
         if (null == tAppUser) {
             tAppUser = new TAppUser();
             tAppUser.setCode(UUIDUtil.getNumberRandom(16));
@@ -559,13 +620,19 @@
             tAppUser.setPassword(Md5Util.MD5Encode("111111", null));
             tAppUser.setIsVip(0);
             tAppUser.setState(1);
+            tAppUser.setHeadImg(headImg);
             tAppUser.setInsertTime(new Date());
             this.baseMapper.insert(tAppUser);
+            String s = generateNickname(tAppUser.getId());
+            tAppUser.setName(s);
+            this.baseMapper.updateById(tAppUser);
         }
         if (tAppUser.getState() == 2) {
             return ResultUtil.error("您的账号已被冻结", "");
         }
         String token = getToken(tAppUser);
+
+        System.out.println("token"+token);
         return ResultUtil.success(token);
     }
 
@@ -589,8 +656,7 @@
                 tAppUser.setPassword(Md5Util.MD5Encode("111111", null));
                 tAppUser.setIsVip(0);
 //                tAppUser.setName(loginWechatVo.getNickname());
-                tAppUser.setName("用户"+loginWechatVo.getPhone().substring(loginWechatVo.getPhone().length() - 4));
-                tAppUser.setHeadImg(loginWechatVo.getHeadimgurl());
+                tAppUser.setHeadImg(headImg);
                 tAppUser.setGender(loginWechatVo.getSex());
                 tAppUser.setState(1);
                 tAppUser.setInsertTime(new Date());
@@ -599,6 +665,11 @@
                 tAppUser.setCity("");
                 tAppUser.setCityCode("");
                 this.baseMapper.insert(tAppUser);
+                // 设置用户昵称为用户+id 保留6位小数 补0
+                String s = generateNickname(tAppUser.getId());
+                tAppUser.setName(s);
+                this.baseMapper.updateById(tAppUser);
+
             }
         }
         if (tAppUser.getState() == 2) {
@@ -624,6 +695,26 @@
         }
         return ResultUtil.success(map);
     }
+    /**
+     * 根据用户ID生成固定格式的昵称
+     * @param userId 用户ID
+     * @return 格式化的昵称
+     */
+    public static String generateNickname(Integer userId) {
+        if (userId == null) {
+            return null;
+        }
+
+        // 将用户ID转换为字符串
+        String userIdStr = String.valueOf(userId);
+
+        // 使用String.format确保总长度为6位,不足的前面补0
+        String formattedId = String.format("%06d", Long.parseLong(userIdStr));
+
+        // 返回"用户" + 格式化后的ID
+        return "用户" + formattedId;
+    }
+
 
     /**
      * 获取JWT token和存储个人信息
@@ -740,6 +831,9 @@
             Store s = null;
             Double d = 0D;
             for (Store store : stores) {
+                if (store == null || !isValidCoordinate(store.getLon(), store.getLat())) {
+                    continue;
+                }
                 Map<String, Double> distance = GeodesyUtil.getDistance(lon + "," + lat, store.getLon() + "," + store.getLat());
                 Double wgs84 = distance.get("WGS84");
                 if (s == null || d > wgs84) {
@@ -747,17 +841,34 @@
                     d = wgs84;
                 }
             }
-            joinPlayPaiVo.setName(s.getName());
-            joinPlayPaiVo.setLon(s.getLon());
-            joinPlayPaiVo.setLat(s.getLat());
-            joinPlayPaiVo.setStoreId(s.getId());
-            joinPlayPaiVo.setPhone(s.getPhone());
-            joinPlayPaiVo.setProvince(s.getProvince());
-            joinPlayPaiVo.setProvinceCode(s.getProvinceCode());
-            joinPlayPaiVo.setCity(s.getCity());
-            joinPlayPaiVo.setCityCode(s.getCityCode());
+            if (s != null) {
+                joinPlayPaiVo.setName(s.getName());
+                joinPlayPaiVo.setLon(s.getLon());
+                joinPlayPaiVo.setLat(s.getLat());
+                joinPlayPaiVo.setStoreId(s.getId());
+                joinPlayPaiVo.setPhone(s.getPhone());
+                joinPlayPaiVo.setProvince(s.getProvince());
+                joinPlayPaiVo.setProvinceCode(s.getProvinceCode());
+                joinPlayPaiVo.setCity(s.getCity());
+                joinPlayPaiVo.setCityCode(s.getCityCode());
+            }
         }
         return joinPlayPaiVo;
+    }
+
+    private boolean isValidCoordinate(String lon, String lat) {
+        if (ToolUtil.isEmpty(lon) || ToolUtil.isEmpty(lat)) {
+            return false;
+        }
+        try {
+            double longitude = Double.parseDouble(lon.trim());
+            double latitude = Double.parseDouble(lat.trim());
+            return Double.isFinite(longitude) && Double.isFinite(latitude)
+                    && longitude >= -180 && longitude <= 180
+                    && latitude >= -90 && latitude <= 90;
+        } catch (NumberFormatException e) {
+            return false;
+        }
     }
 
     @Override
@@ -1277,6 +1388,34 @@
     @Override
     public ResultUtil<String> updateInfo(UpdateInfoDto dto, Integer uid) {
         TAppUser tAppUser = appUserMapper.selectById(uid);
+        if (StringUtils.hasLength(dto.getName())){
+            if (!tAppUser.getName().equals(dto.getName())){
+                TUserAudit userAudit = userAuditService
+                        .lambdaQuery().eq(TUserAudit::getType, 1)
+                        .eq(TUserAudit::getAppUserId, tAppUser.getId())
+                        .ne(TUserAudit::getState, 2).last("limit 1").one();
+                if (userAudit!=null){
+                    userAudit.setState(1);
+                    userAudit.setName(dto.getName());
+                    UpdateWrapper<TUserAudit> tUserAuditUpdateWrapper = new UpdateWrapper<>();
+                    tUserAuditUpdateWrapper.eq("id",userAudit.getId());
+                    tUserAuditUpdateWrapper.set("state",1);
+                    tUserAuditUpdateWrapper.set("name",dto.getName());
+                    tUserAuditUpdateWrapper.set("remarks",null);
+                    tUserAuditUpdateWrapper.set("auditId",null);
+                    tUserAuditUpdateWrapper.set("auditTime",null);
+                    userAuditService.update(tUserAuditUpdateWrapper);
+                }else{
+                    TUserAudit tUserAudit = new TUserAudit();
+                    tUserAudit.setAppUserId(tAppUser.getId());
+                    tUserAudit.setName(dto.getName());
+                    tUserAudit.setType(1);
+                    tUserAudit.setInsertTime(new Date());
+                    userAuditService.save(tUserAudit);
+
+                }
+            }
+        }
         if (ToolUtil.isNotEmpty(dto.getName())) {
             tAppUser.setName(dto.getName());
         }
@@ -1293,6 +1432,7 @@
         if (ToolUtil.isNotEmpty(dto.getGender())) {
             tAppUser.setGender(dto.getGender());
         }
+        tAppUser.setName(null);
         appUserMapper.updateById(tAppUser);
         return ResultUtil.success();
     }
@@ -1341,6 +1481,10 @@
     @Override
     @Transactional
     public synchronized ResultUtil productRedemptionOperation(Integer userIdFormRedis, GoodsExchangeVo exchangeType) {
+        // 兼容前端历史参数 chooseCouponId,内部统一使用 couponId。
+        if (exchangeType.getCouponId() == null && exchangeType.getChooseCouponId() != null) {
+            exchangeType.setCouponId(exchangeType.getChooseCouponId());
+        }
         ReturnModel returnModel = new ReturnModel();
         Long returnId = null;
         //如果是兑换优惠卷
@@ -1434,6 +1578,51 @@
                 return ResultUtil.error("商品不存在");
             }
 
+            BigDecimal cashAmount = merchandise.getCash() == null ? BigDecimal.ZERO : merchandise.getCash();
+            // 门票优惠后的订单现金应付总额;支付参数必须使用该金额,不能再使用商品原价。
+            BigDecimal ticketPayableCashAmount = null;
+            UserCoupon usedCoupon = null;
+            if (exchangeType.getGoodsType() == 3 && exchangeType.getCouponId() != null && exchangeType.getCouponId() != 0) {
+                if (exchangeType.getExchangeType() == 1) {
+                    return ResultUtil.error("积分兑换不能使用优惠券");
+                }
+                usedCoupon = userConponClient.queryUserCouponById(
+                        new QueryUserCouponByIdAndUserId(exchangeType.getCouponId(), userIdFormRedis));
+                if (usedCoupon == null || !Integer.valueOf(1).equals(usedCoupon.getStatus())) {
+                    return ResultUtil.error("优惠券不可用");
+                }
+                Coupon coupon = userConponClient.queryCouponById(usedCoupon.getCouponId());
+                if (coupon == null || coupon.getEndTime() == null || !coupon.getEndTime().after(new Date())) {
+                    return ResultUtil.error("优惠券已过期");
+                }
+                if (Integer.valueOf(3).equals(coupon.getUseScope())
+                        && (exchangeType.getStoreId() == null || !userConponClient.getCouponStoreIds(coupon.getId()).contains(exchangeType.getStoreId()))) {
+                    return ResultUtil.error("该优惠券不适用于所选门店");
+                }
+                BigDecimal orderCash = cashAmount.multiply(BigDecimal.valueOf(exchangeType.getNums() == null ? 1 : exchangeType.getNums()));
+                JSONObject rule = JSON.parseObject(coupon.getContent());
+                if (Integer.valueOf(1).equals(coupon.getType())) {
+                    BigDecimal condition = rule.getBigDecimal("conditionalAmount");
+                    BigDecimal deduction = rule.getBigDecimal("deductionAmount");
+                    if (condition == null || deduction == null || orderCash.compareTo(condition) < 0) {
+                        return ResultUtil.error("该优惠券无法使用");
+                    }
+                    cashAmount = orderCash.subtract(deduction).max(BigDecimal.ZERO)
+                            .divide(BigDecimal.valueOf(exchangeType.getNums() == null ? 1 : exchangeType.getNums()), 2, java.math.RoundingMode.HALF_UP);
+                } else if (Integer.valueOf(2).equals(coupon.getType())) {
+                    BigDecimal deduction = rule.getBigDecimal("conditionalAmount");
+                    if (deduction == null || deduction.compareTo(BigDecimal.ZERO) <= 0) {
+                        return ResultUtil.error("该优惠券无法使用");
+                    }
+                    // 代金券可覆盖全部订单金额,超出订单金额的部分不找零。
+                    ticketPayableCashAmount = orderCash.subtract(deduction).max(BigDecimal.ZERO);
+                    cashAmount = ticketPayableCashAmount
+                            .divide(BigDecimal.valueOf(exchangeType.getNums() == null ? 1 : exchangeType.getNums()), 2, java.math.RoundingMode.HALF_UP);
+                } else {
+                    return ResultUtil.error("该优惠券不支持购买门票");
+                }
+            }
+
             TAppUser tAppUser = this.baseMapper.selectById(userIdFormRedis);
 
             if (merchandise.getUserPopulation() == 2) {
@@ -1458,6 +1647,9 @@
             } else {
                 goodsNums = exchangeType.getNums();
             }
+            BigDecimal cashPaymentAmount = ticketPayableCashAmount == null
+                    ? cashAmount.multiply(BigDecimal.valueOf(goodsNums))
+                    : ticketPayableCashAmount;
 
             TAppUser user = appUserService.getById(userIdFormRedis);
             if (merchandise.getIntegral() != null) {
@@ -1494,6 +1686,10 @@
             if (exchangeType.getExchangeType() == 1) {
                 pointsMerchandise.setPayStatus(2);
                 pointsMerchandise.setPaymentTime(new Date());
+            } else if (cashPaymentAmount.compareTo(BigDecimal.ZERO) == 0) {
+                // 优惠券将现金部分完全抵扣时,不能向第三方支付发起 0 元或原价支付。
+                pointsMerchandise.setPayStatus(2);
+                pointsMerchandise.setPaymentTime(new Date());
             } else {
                 pointsMerchandise.setPayStatus(1);
             }
@@ -1508,26 +1704,37 @@
             pointsMerchandise.setCode(code);
             pointsMerchandise.setInsertTime(new Date());
             pointsMerchandise.setPayType(exchangeType.getExchangeType());
+            pointsMerchandise.setUserCouponId(exchangeType.getGoodsType() == 3 ? exchangeType.getCouponId() : null);
             if (null != merchandise.getIntegral()) {
                 pointsMerchandise.setIntegral(merchandise.getIntegral() * goodsNums);
             }
             if (exchangeType.getExchangeType() == 2 || exchangeType.getExchangeType() == 3) {
-                pointsMerchandise.setCash(merchandise.getCash());
+                pointsMerchandise.setCash(exchangeType.getGoodsType() == 3 ? cashPaymentAmount : cashAmount);
                 pointsMerchandise.setCashPayType(exchangeType.getPayType());
             }
 
-            Double m = new BigDecimal((merchandise.getIntegral() == null ? 0 : merchandise.getIntegral())).add((merchandise.getCash() == null ? BigDecimal.ZERO : merchandise.getCash())).doubleValue();
+            Double m = new BigDecimal((merchandise.getIntegral() == null ? 0 : merchandise.getIntegral())).add(cashAmount).doubleValue();
             if ((m * goodsNums) == 0) {
                 pointsMerchandise.setPayStatus(2);
                 pointsMerchandise.setPaymentTime(new Date());
             }
             returnId = mcClient.saveDetailsUserPointMercase(pointsMerchandise);
+            if (usedCoupon != null) {
+                usedCoupon.setStatus(2);
+                userConponClient.updateUserCoupon(usedCoupon);
+            }
             if(goodsNums>1){
                 System.err.println("购买商品数量"+goodsNums);
                 List<UserPointsMerchandise> userPointsMerchandises = new ArrayList<>();
                 for (int i = 1; i < goodsNums; i++) {
                     UserPointsMerchandise userPointsMerchandise = new UserPointsMerchandise();
                     BeanUtils.copyProperties(pointsMerchandise, userPointsMerchandise);
+                    // 一笔订单只能关联一次优惠券,避免拆分门票后重复计入优惠金额。
+                    userPointsMerchandise.setUserCouponId(null);
+                    if (exchangeType.getGoodsType() == 3) {
+                        // 门票拆单后仅首条保留订单总实付金额,避免支付/收入统计重复累加。
+                        userPointsMerchandise.setCash(BigDecimal.ZERO);
+                    }
                     userPointsMerchandises.add(userPointsMerchandise);
                 }
                 System.err.println("新增额外购买记录"+userPointsMerchandises);
@@ -1539,8 +1746,16 @@
                 }
 
             }
-            if ((m * goodsNums) == 0 && pointsMerchandise.getPayStatus() == 2) {
+            if (pointsMerchandise.getPayStatus() == 2 && exchangeType.getExchangeType() != 1
+                    && cashPaymentAmount.compareTo(BigDecimal.ZERO) == 0) {
+                // 积分+现金商品被优惠券抵扣为零元时,仍需扣除积分;不等待支付回调。
+                if (exchangeType.getExchangeType() == 2 && merchandise.getIntegral() != null
+                        && merchandise.getIntegral() > 0
+                        && !dealAppUserIntegral(userIdFormRedis, tAppUser, merchandise.getIntegral() * goodsNums)) {
+                    return ResultUtil.error("用户积分不足!");
+                }
                 returnModel.setReturnId(returnId);
+                returnModel.setPaySuccess(true);
                 return ResultUtil.success(returnModel);
             }
 
@@ -1628,7 +1843,7 @@
                                             break;
                                         }
                                     }
-                                    coursePackageOrder.setCashPayment(merchandise.getCash().multiply(new BigDecimal(exchangeType.getStuIds().size())));
+                                    coursePackageOrder.setCashPayment(cashAmount.multiply(new BigDecimal(exchangeType.getStuIds().size())));
                                     coursePackageOrder.setPlayPaiCoin(merchandise.getIntegral() * exchangeType.getStuIds().size());
                                     coursePackageOrder.setPayUserType(1);
                                     coursePackageOrder.setPayStatus(1);
@@ -1638,20 +1853,22 @@
                                     coursePackageOrder.setInsertTime(new Date());
                                     coursePackageOrder.setOrderType(2);
                                     paymentClient.savePaymentCoursePackage(coursePackageOrder);
-                                    return WechatPayment(merchandise.getType(), merchandise.getCash().multiply(new BigDecimal(exchangeType.getStuIds().size())), code, merchandise.getId());
+                                    return WechatPayment(merchandise.getType(), cashAmount.multiply(new BigDecimal(exchangeType.getStuIds().size())), code, merchandise.getId());
                                 } else if (merchandise.getType() == 1) {
-                                    return WechatPayment(merchandise.getType(), merchandise.getCash().multiply(new BigDecimal(goodsNums)), code, merchandise.getId());
+                                    return WechatPayment(merchandise.getType(), cashAmount.multiply(new BigDecimal(goodsNums)), code, merchandise.getId());
                                 } else if (merchandise.getType() == 3) {
-                                    return WechatPayment(merchandise.getType(), merchandise.getCash().multiply(new BigDecimal(goodsNums)), code, merchandise.getId());
+                                    return WechatPayment(merchandise.getType(), cashPaymentAmount, code, merchandise.getId());
                                 }
                             } catch (Exception e) {
                                 return ResultUtil.runErr();
                             }
                         case 2:
                             if (merchandise.getType() == 2) {
-                                return AlipayPayment(merchandise.getType(), merchandise.getCash().multiply(new BigDecimal(exchangeType.getStuIds().size())), code, merchandise.getId());
+                                return AlipayPayment(merchandise.getType(), cashAmount.multiply(new BigDecimal(exchangeType.getStuIds().size())), code, merchandise.getId());
+                            } else if (merchandise.getType() == 3) {
+                                return AlipayPayment(merchandise.getType(), cashPaymentAmount, code, merchandise.getId());
                             } else {
-                                return AlipayPayment(merchandise.getType(), merchandise.getCash().multiply(new BigDecimal(goodsNums)), code, merchandise.getId());
+                                return AlipayPayment(merchandise.getType(), cashAmount.multiply(new BigDecimal(goodsNums)), code, merchandise.getId());
                             }
                         default:
                             break;
@@ -1662,18 +1879,22 @@
                         case 1:
                             try {
                                 if (merchandise.getType() == 2) {
-                                    return WechatPayment(merchandise.getType(), merchandise.getCash().multiply(new BigDecimal(exchangeType.getStuIds().size())), code, merchandise.getId());
+                                    return WechatPayment(merchandise.getType(), cashAmount.multiply(new BigDecimal(exchangeType.getStuIds().size())), code, merchandise.getId());
+                                } else if (merchandise.getType() == 3) {
+                                    return WechatPayment(merchandise.getType(), cashPaymentAmount, code, merchandise.getId());
                                 } else {
-                                    return WechatPayment(merchandise.getType(), merchandise.getCash().multiply(new BigDecimal(goodsNums)), code, merchandise.getId());
+                                    return WechatPayment(merchandise.getType(), cashAmount.multiply(new BigDecimal(goodsNums)), code, merchandise.getId());
                                 }
                             } catch (Exception e) {
                                 return ResultUtil.runErr();
                             }
                         case 2:
                             if (merchandise.getType() == 2) {
-                                return AlipayPayment(merchandise.getType(), merchandise.getCash().multiply(new BigDecimal(exchangeType.getStuIds().size())), code, merchandise.getId());
+                                return AlipayPayment(merchandise.getType(), cashAmount.multiply(new BigDecimal(exchangeType.getStuIds().size())), code, merchandise.getId());
+                            } else if (merchandise.getType() == 3) {
+                                return AlipayPayment(merchandise.getType(), cashPaymentAmount, code, merchandise.getId());
                             } else {
-                                return AlipayPayment(merchandise.getType(), merchandise.getCash().multiply(new BigDecimal(goodsNums)), code, merchandise.getId());
+                                return AlipayPayment(merchandise.getType(), cashAmount.multiply(new BigDecimal(goodsNums)), code, merchandise.getId());
                             }
                         default:
                             break;
@@ -1684,6 +1905,7 @@
             }
 
             returnModel.setReturnId(returnId);
+            returnModel.setPaySuccess(pointsMerchandise.getPayStatus() == 2);
             return ResultUtil.success(returnModel);
         } catch (Exception e) {
             e.printStackTrace();
@@ -2038,7 +2260,20 @@
                 }
             }).start();
         }
-        return alipay;
+        return appendPaySuccess(alipay);
+    }
+
+    /**
+     * 支付宝、微信的成功响应仅表示已生成支付单,客户端仍需拉起第三方支付。
+     */
+    private ResultUtil appendPaySuccess(ResultUtil paymentResult) {
+        JSONObject data = paymentResult.getData() == null ? new JSONObject()
+                : JSON.parseObject(JSON.toJSONString(paymentResult.getData()));
+        if (data == null) {
+            data = new JSONObject();
+        }
+        data.put("paySuccess", false);
+        return ResultUtil.getResult(paymentResult.getCode(), paymentResult.getMsg(), data);
     }
 
 
@@ -2060,7 +2295,7 @@
                         // 平台门票
                         ResultUtil weixinpay = payMoneyUtil.weixinpay(name, "", code, cash.toString(),
                                 "/base/pointMer/exchangeGoodPaymentWeChatCallback", "APP", "");
-                        return weixinpay;
+                        return appendPaySuccess(weixinpay);
                     } else {
                         String s2 = storeClient.getmerchantNumberByOperatorId(store1.getOperatorId());
                         System.err.println("微信商户号" + s2);
@@ -2071,7 +2306,7 @@
                         ResultUtil weixinpay = payMoneyUtil.weixinpayV3(s2, name, code,
                                 "/base/pointMer/exchangeGoodPaymentWeChatCallback1",
                                 cash.toString());
-                        return weixinpay;
+                        return appendPaySuccess(weixinpay);
                     }
                 }
                 break;
@@ -2083,7 +2318,7 @@
                     // 平台课包
                     ResultUtil weixinpay = payMoneyUtil.weixinpay(name, "", code, cash.toString(),
                             "/base/pointMer/exchangeGoodPaymentWeChatCallback", "APP", "");
-                    return weixinpay;
+                    return appendPaySuccess(weixinpay);
                 } else {
                     String s2 = storeClient.getmerchantNumberByOperatorId(store.getOperatorId());
                     System.err.println("微信商户号" + s2);
@@ -2094,7 +2329,7 @@
                     ResultUtil weixinpay = payMoneyUtil.weixinpayV3(s2, name, code,
                             "/base/pointMer/exchangeGoodPaymentWeChatCallback1",
                             cash.toString());
-                    return weixinpay;
+                    return appendPaySuccess(weixinpay);
                 }
             case 3:
                 if (!integers.isEmpty()) {
@@ -2103,7 +2338,7 @@
                         // 平台门票
                         ResultUtil weixinpay = payMoneyUtil.weixinpay(name, "", code, cash.toString(),
                                 "/base/pointMer/exchangeGoodPaymentWeChatCallback", "APP", "");
-                        return weixinpay;
+                        return appendPaySuccess(weixinpay);
                     } else {
                         String s2 = storeClient.getmerchantNumberByOperatorId(store1.getOperatorId());
                         System.err.println("微信商户号" + s2);
@@ -2114,13 +2349,13 @@
                         ResultUtil weixinpay = payMoneyUtil.weixinpayV3(s2, name, code,
                                 "/base/pointMer/exchangeGoodPaymentWeChatCallback1",
                                 cash.toString());
-                        return weixinpay;
+                        return appendPaySuccess(weixinpay);
                     }
                 } else {
                     // 平台门票
                     ResultUtil weixinpay = payMoneyUtil.weixinpay(name, "", code, cash.toString(),
                             "/base/pointMer/exchangeGoodPaymentWeChatCallback", "APP", "");
-                    return weixinpay;
+                    return appendPaySuccess(weixinpay);
 
                 }
         }

--
Gitblit v1.7.1