刘帅
2026-09-20 8a85fc834d98b2c14c5b886a957ccf3197aad293
feat:优惠券使用入口:购买门票、预定场地、购买惠民卡
2个文件已添加
18个文件已修改
246 ■■■■■ 已修改文件
cloud-server-account/src/main/java/com/dsh/account/feignclient/activity/UserConponClient.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
cloud-server-account/src/main/java/com/dsh/account/feignclient/activity/model/QueryUserCouponByIdAndUserId.java 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
cloud-server-account/src/main/java/com/dsh/account/feignclient/activity/model/UserPointsMerchandise.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
cloud-server-account/src/main/java/com/dsh/account/model/vo/userBenefitDetail/GoodsExchangeVo.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
cloud-server-account/src/main/java/com/dsh/account/service/impl/TAppUserServiceImpl.java 74 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
cloud-server-activity/src/main/java/com/dsh/activity/controller/HuiminController.java 55 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
cloud-server-activity/src/main/java/com/dsh/activity/controller/UserCouponController.java 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
cloud-server-activity/src/main/java/com/dsh/activity/entity/TPayHuimin.java 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
cloud-server-activity/src/main/java/com/dsh/activity/entity/UserPointsMerchandise.java 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
cloud-server-activity/src/main/java/com/dsh/activity/model/PointMerchandiseIncomeVo.java 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
cloud-server-activity/src/main/java/com/dsh/activity/model/response/SalesDetailVO.java 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
cloud-server-activity/src/main/java/com/dsh/activity/service/UserCouponService.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
cloud-server-activity/src/main/java/com/dsh/activity/service/impl/UserCouponServiceImpl.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
cloud-server-activity/src/main/resources/mapper/PayHuiminMapper.xml 4 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
cloud-server-activity/src/main/resources/mapper/UserPointsMerchandiseMapper.xml 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
cloud-server-management/src/main/java/com/dsh/guns/modular/system/controller/code/DataStatisticsController.java 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
cloud-server-management/src/main/java/com/dsh/guns/modular/system/model/PointMerchandiseIncomeVo.java 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
cloud-server-management/src/main/java/com/dsh/guns/modular/system/model/SalesDetailVO.java 1 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
cloud-server-other/src/main/java/com/dsh/other/service/impl/SiteServiceImpl.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
sql/V20260920__add_coupon_to_ticket_and_huimin_orders.sql 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
cloud-server-account/src/main/java/com/dsh/account/feignclient/activity/UserConponClient.java
@@ -3,6 +3,7 @@
import com.dsh.account.feignclient.activity.model.CommodityRequest;
import com.dsh.account.feignclient.activity.model.GrantCoupon;
import com.dsh.account.feignclient.activity.model.UserCoupon;
import com.dsh.account.feignclient.activity.model.QueryUserCouponByIdAndUserId;
import com.dsh.account.model.dto.Coupon;
import com.dsh.account.model.vo.sourceDetail.CouponStuAvailableVo;
import org.springframework.cloud.openfeign.FeignClient;
@@ -49,4 +50,10 @@
    void grantCoupon(@RequestBody GrantCoupon grantCoupon);
    @GetMapping("/userCoupon/setStatusVipDetail/{id}")
    void setStatusVipDetail(@PathVariable("id") Integer id);
    @PostMapping("/userCoupon/queryUserCouponById")
    UserCoupon queryUserCouponById(@RequestBody QueryUserCouponByIdAndUserId query);
    @PostMapping("/userCoupon/updateUserCoupon")
    void updateUserCoupon(@RequestBody UserCoupon userCoupon);
}
cloud-server-account/src/main/java/com/dsh/account/feignclient/activity/model/QueryUserCouponByIdAndUserId.java
New file
@@ -0,0 +1,13 @@
package com.dsh.account.feignclient.activity.model;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class QueryUserCouponByIdAndUserId {
    private Long id;
    private Integer userId;
}
cloud-server-account/src/main/java/com/dsh/account/feignclient/activity/model/UserPointsMerchandise.java
@@ -123,4 +123,7 @@
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private Date paymentTime;
    @TableField("userCouponId")
    private Long userCouponId;
}
cloud-server-account/src/main/java/com/dsh/account/model/vo/userBenefitDetail/GoodsExchangeVo.java
@@ -33,4 +33,7 @@
    @ApiModelProperty(value = "门店id", required = false)
    Integer storeId;
    @ApiModelProperty(value = "用户优惠券领取记录id;仅购买门票且现金支付时可传", required = false)
    Long couponId;
}
cloud-server-account/src/main/java/com/dsh/account/service/impl/TAppUserServiceImpl.java
@@ -12,6 +12,8 @@
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;
@@ -1572,6 +1574,47 @@
                return ResultUtil.error("商品不存在");
            }
            BigDecimal cashAmount = merchandise.getCash() == null ? BigDecimal.ZERO : merchandise.getCash();
            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) {
                        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 {
                    return ResultUtil.error("该优惠券不支持购买门票");
                }
            }
            TAppUser tAppUser = this.baseMapper.selectById(userIdFormRedis);
            if (merchandise.getUserPopulation() == 2) {
@@ -1646,26 +1689,33 @@
            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(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);
                    userPointsMerchandises.add(userPointsMerchandise);
                }
                System.err.println("新增额外购买记录"+userPointsMerchandises);
@@ -1766,7 +1816,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);
@@ -1776,20 +1826,20 @@
                                    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(), 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 {
                                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;
@@ -1800,18 +1850,18 @@
                        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 {
                                    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 {
                                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;
cloud-server-activity/src/main/java/com/dsh/activity/controller/HuiminController.java
@@ -81,6 +81,10 @@
    private HuiminRecordService huiminRecordService;
    @Resource
    private StudentClient studentClient;
    @Resource
    private UserCouponService userCouponService;
    @Resource
    private CouponStoreService couponStoreService;
    @Autowired
@@ -99,9 +103,10 @@
            @ApiImplicitParam(value = "玩湃惠民卡id", name = "id", dataType = "int", required = true),
            @ApiImplicitParam(value = "支付方式1微信2支付宝", name = "payType", dataType = "int", required = true),
            @ApiImplicitParam(value = "绑定学员ids多,个逗号拼接", name = "studentIds", dataType = "String", required = true),
            @ApiImplicitParam(value = "用户优惠券领取记录id;不使用时不传", name = "couponId", dataType = "long", required = false),
            @ApiImplicitParam(name = "Authorization", value = "用户token(Bearer +token)", required = true, dataType = "String", paramType = "header", defaultValue = "Bearer eyJhbGciOiJIUzUxMiJ9.....")
    })
    public ResultUtil<THuiminCard> payHuiminCard(Integer id, Integer payType, String studentIds) {
    public ResultUtil<THuiminCard> payHuiminCard(Integer id, Integer payType, String studentIds, Long couponId) {
        try {
            Integer uid = tokenUtil.getUserIdFormRedis();
            if (null == uid) {
@@ -128,7 +133,48 @@
            TPayHuimin tPayHuimin = new TPayHuimin();
            String[] split = studentIds.split(",");
            tPayHuimin.setSalesMoney(huiminCard.getSalesMoney().multiply(new BigDecimal(split.length)).setScale(2));
            BigDecimal salesMoney = huiminCard.getSalesMoney().multiply(new BigDecimal(split.length)).setScale(2);
            UserCoupon userCoupon = null;
            if (couponId != null && couponId != 0) {
                if (payType != 1 && payType != 2) {
                    return ResultUtil.error("优惠券仅支持微信或支付宝支付");
                }
                userCoupon = userCouponService.getById(couponId);
                if (userCoupon == null || !uid.equals(userCoupon.getUserId()) || !Integer.valueOf(1).equals(userCoupon.getStatus())) {
                    return ResultUtil.error("优惠券不可用");
                }
                Coupon coupon = couponService.getById(userCoupon.getCouponId());
                if (coupon == null || coupon.getEndTime() == null || !coupon.getEndTime().after(new Date())) {
                    return ResultUtil.error("优惠券已过期");
                }
                if (Integer.valueOf(3).equals(coupon.getUseScope())) {
                    Set<Integer> cardStoreIds = Arrays.stream((huiminCard.getStoreIds() == null ? "" : huiminCard.getStoreIds()).split(","))
                            .filter(value -> !value.trim().isEmpty()).map(Integer::valueOf).collect(Collectors.toSet());
                    boolean available = couponStoreService.lambdaQuery().eq(CouponStore::getCouponId, coupon.getId()).list()
                            .stream().map(CouponStore::getStoreId).anyMatch(cardStoreIds::contains);
                    if (!available) {
                        return ResultUtil.error("该优惠券不适用于此惠民卡");
                    }
                }
                if (coupon.getType() == 1) {
                    JSONObject rule = JSON.parseObject(coupon.getContent());
                    BigDecimal condition = rule.getBigDecimal("conditionalAmount");
                    BigDecimal deduction = rule.getBigDecimal("deductionAmount");
                    if (condition == null || deduction == null || salesMoney.compareTo(condition) < 0) {
                        return ResultUtil.error("该优惠券无法使用");
                    }
                    salesMoney = salesMoney.subtract(deduction).max(BigDecimal.ZERO).setScale(2);
                } else if (coupon.getType() == 2) {
                    BigDecimal deduction = JSON.parseObject(coupon.getContent()).getBigDecimal("conditionalAmount");
                    if (deduction == null) {
                        return ResultUtil.error("该优惠券无法使用");
                    }
                    salesMoney = salesMoney.subtract(deduction).max(BigDecimal.ZERO).setScale(2);
                } else {
                    return ResultUtil.error("该优惠券不支持购买惠民卡");
                }
            }
            tPayHuimin.setSalesMoney(salesMoney);
            tPayHuimin.setAppUserId(uid);
            tPayHuimin.setStudentId(studentIds);
            switch (huiminCard.getHuiMinType()) {
@@ -155,10 +201,15 @@
            tPayHuimin.setPaymentType(payType);
            tPayHuimin.setRefundStatus(1);
            tPayHuimin.setCardId(huiminCard.getId());
            tPayHuimin.setUserCouponId(couponId);
            SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS");
            tPayHuimin.setCode(sdf.format(new Date()) + UUIDUtil.getNumberRandom(5));
            System.err.println("支付数据" + tPayHuimin);
            payHuiminService.save(tPayHuimin);
            if (userCoupon != null) {
                userCoupon.setStatus(2);
                userCouponService.updateById(userCoupon);
            }
            BigDecimal bigDecimal = new BigDecimal(studentIds.split(",").length);
            if (tPayHuimin.getSalesMoney().compareTo(BigDecimal.ZERO)==0){
                // 零元购
cloud-server-activity/src/main/java/com/dsh/activity/controller/UserCouponController.java
@@ -201,6 +201,25 @@
        }
    }
    @ResponseBody
    @PostMapping("/api/coupon/queryStoreCouponList")
    @ApiOperation(value = "订单支付页可用优惠券列表(购买门票、购买惠民卡)")
    public ResultUtil<List<CouponListVo>> queryStoreCouponList(Integer storeId, Double price, String lon, String lat) {
        try {
            Integer uid = tokenUtil.getUserIdFormRedis();
            if (uid == null) {
                return ResultUtil.tokenErr();
            }
            if (storeId == null || price == null || price < 0) {
                return ResultUtil.error("门店和订单金额不能为空");
            }
            return ResultUtil.success(userCouponService.queryStoreCouponList(uid, storeId, price, lon, lat));
        } catch (Exception e) {
            e.printStackTrace();
            return ResultUtil.runErr();
        }
    }
    /**
     * 根据id获取用户优惠券数据
cloud-server-activity/src/main/java/com/dsh/activity/entity/TPayHuimin.java
@@ -110,6 +110,10 @@
    @TableField("refundNumber")
    private String refundNumber;
    /** 本次购买使用的用户优惠券领取记录 ID */
    @TableField("userCouponId")
    private Long userCouponId;
    /**
     * 已购数量
     */
cloud-server-activity/src/main/java/com/dsh/activity/entity/UserPointsMerchandise.java
@@ -134,6 +134,10 @@
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private Date paymentTime;
    /** 本次购买使用的用户优惠券领取记录 ID */
    @TableField("userCouponId")
    private Long userCouponId;
    @Override
    protected Serializable pkVal() {
cloud-server-activity/src/main/java/com/dsh/activity/model/PointMerchandiseIncomeVo.java
@@ -20,4 +20,5 @@
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    private Date insertTime;
    private BigDecimal cash;
    private Long userCouponId;
}
cloud-server-activity/src/main/java/com/dsh/activity/model/response/SalesDetailVO.java
@@ -44,4 +44,5 @@
    private Integer useTimes;           // 已用次数
    private Integer status;             // 状态(1:使用中,2:已退款)
    private String orderNumber;             // 支付流水号
    private Long userCouponId;
}
cloud-server-activity/src/main/java/com/dsh/activity/service/UserCouponService.java
@@ -41,6 +41,9 @@
     */
    List<CouponListVo> querySiteCouponList(Integer uid, Integer siteId, Double price, String lon, String lat) throws Exception;
    /** 获取指定门店、指定订单金额可使用的优惠券(门票、惠民卡支付页复用)。 */
    List<CouponListVo> queryStoreCouponList(Integer uid, Integer storeId, Double price, String lon, String lat) throws Exception;
    List<CouponPackageResp> queryCouponPackagesList(Integer uid, CouponPackageReq req);
cloud-server-activity/src/main/java/com/dsh/activity/service/impl/UserCouponServiceImpl.java
@@ -128,7 +128,10 @@
        }
        try {
            JSONObject content = JSON.parseObject(coupon.getContent());
            BigDecimal deductionAmount = content.getBigDecimal("deductionAmount");
            // 满减券使用 deductionAmount,代金券历史规则将抵扣额存放在 conditionalAmount。
            BigDecimal deductionAmount = Integer.valueOf(2).equals(coupon.getType())
                    ? content.getBigDecimal("conditionalAmount")
                    : content.getBigDecimal("deductionAmount");
            return deductionAmount == null ? BigDecimal.ZERO : deductionAmount.max(BigDecimal.ZERO);
        } catch (Exception e) {
            LOGGER.warn("解析优惠券抵扣规则失败,couponId={}", coupon.getId(), e);
@@ -155,6 +158,10 @@
        List<CouponListVo> listVos = new ArrayList<>();
        for (Map<String, Object> userCoupon : userCoupons) {
            Integer type = Integer.valueOf(userCoupon.get("type").toString());
            // 支付减免只支持满减券和代金券;体验券/抵扣券不能用于订单金额计算。
            if (type != 1 && type != 2) {
                continue;
            }
            CouponListVo couponListVo = new CouponListVo();
            couponListVo.setId(Long.valueOf(userCoupon.get("id").toString()));
            couponListVo.setName(userCoupon.get("name").toString());
@@ -204,7 +211,11 @@
    @Override
    public List<CouponListVo> querySiteCouponList(Integer uid, Integer siteId, Double price, String lon, String lat) throws Exception {
        Site site = siteClient.querySiteById(siteId);
        Integer storeId = site.getStoreId();
        return queryStoreCouponList(uid, site.getStoreId(), price, lon, lat);
    }
    @Override
    public List<CouponListVo> queryStoreCouponList(Integer uid, Integer storeId, Double price, String lon, String lat) throws Exception {
        Map<String, String> geocode = gdMapGeocodingUtil.geocode(lon, lat);
        String provinceCode = geocode.get("provinceCode");
        String cityCode = geocode.get("cityCode");
@@ -212,6 +223,9 @@
        List<CouponListVo> listVos = new ArrayList<>();
        for (Map<String, Object> userCoupon : userCoupons) {
            Integer type = Integer.valueOf(userCoupon.get("type").toString());
            if (type != 1 && type != 2) {
                continue;
            }
            CouponListVo couponListVo = new CouponListVo();
            couponListVo.setId(Long.valueOf(userCoupon.get("id").toString()));
            couponListVo.setName(userCoupon.get("name").toString());
cloud-server-activity/src/main/resources/mapper/PayHuiminMapper.xml
@@ -20,7 +20,8 @@
        tph.studentId,
        thc.id as carId,
        tph.status,
        tph.orderNumber
        tph.orderNumber,
        tph.userCouponId
        FROM
        t_pay_huimin tph
        LEFT JOIN t_huimin_card thc ON tph.cardId = thc.id
@@ -138,6 +139,7 @@
        tph.endTime,
        tph.studentId,
        tph.status,
        tph.userCouponId,
        CASE
        WHEN tph.id IS NULL THEN NULL
        ELSE COALESCE(COUNT(thr.id), 0)
cloud-server-activity/src/main/resources/mapper/UserPointsMerchandiseMapper.xml
@@ -18,7 +18,7 @@
    <select id="getAmount" resultType="com.dsh.activity.model.PointMerchandiseIncomeVo">
        select COALESCE(t1.paymentTime, t1.insertTime) as insertTime, t1.cash from t_user_points_merchandise t1
        select COALESCE(t1.paymentTime, t1.insertTime) as insertTime, t1.cash, t1.userCouponId from t_user_points_merchandise t1
        left join t_points_merchandise t2 on t1.pointsMerchandiseId = t2.id
        where t1.payStatus = 2
        and (t1.state is null or t1.state = 1)
cloud-server-management/src/main/java/com/dsh/guns/modular/system/controller/code/DataStatisticsController.java
@@ -448,12 +448,9 @@
            }
        }
        Map<Long, BigDecimal> couponDeductionAmounts = getCouponDeductionAmounts(usedCouponIds);
        applyCouponDeductions(incomeVOS, couponDeductionAmounts);
        // 惠民卡和优惠券购买不归属到单一课程/场地门店,当前仅在平台或运营商汇总中计入。
        if (storeId == null) {
            appendHuiminIncome(incomeVOS, operatorId);
            appendHuiminIncome(incomeVOS, operatorId, usedCouponIds);
            if (operatorId == null) {
                appendCouponPurchaseIncome(incomeVOS);
            }
@@ -468,9 +465,15 @@
            temp.setInsertTime(pointMerchandiseIncomeVo.getInsertTime());
            if (pointMerchandiseIncomeVo.getCash()!=null){
                temp.setAmount(pointMerchandiseIncomeVo.getCash());
                if (pointMerchandiseIncomeVo.getUserCouponId() != null) {
                    usedCouponIds.add(pointMerchandiseIncomeVo.getUserCouponId());
                    temp.setId(pointMerchandiseIncomeVo.getUserCouponId().toString());
                }
                incomeVOS.add(temp);
            }
        }
        Map<Long, BigDecimal> couponDeductionAmounts = getCouponDeductionAmounts(usedCouponIds);
        applyCouponDeductions(incomeVOS, couponDeductionAmounts);
        // 平台智慧球场
        if (storeId==null&&operatorId==null){
            gameDataQuery.setObjectId(0);
@@ -538,7 +541,7 @@
    }
    /** 惠民卡采用支付、退款两条事实流水,赠送卡不计营收。 */
    private void appendHuiminIncome(List<IncomeVO> incomeRecords, Integer operatorId) {
    private void appendHuiminIncome(List<IncomeVO> incomeRecords, Integer operatorId, Set<Long> usedCouponIds) {
        HuiminPayQuery query = new HuiminPayQuery();
        query.setGiftPaymentType(3);
        if (operatorId != null) {
@@ -556,6 +559,10 @@
            payment.setIncomeType(6);
            payment.setInsertTime(record.getPaymentTime());
            payment.setAmount(record.getSalesMoney());
            if (record.getUserCouponId() != null) {
                usedCouponIds.add(record.getUserCouponId());
                payment.setId(record.getUserCouponId().toString());
            }
            incomeRecords.add(payment);
            if (Integer.valueOf(3).equals(record.getStatus())
                    || Integer.valueOf(2).equals(record.getRefundStatus())
cloud-server-management/src/main/java/com/dsh/guns/modular/system/model/PointMerchandiseIncomeVo.java
@@ -18,4 +18,5 @@
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
    private Date insertTime;
    private BigDecimal cash;
    private Long userCouponId;
}
cloud-server-management/src/main/java/com/dsh/guns/modular/system/model/SalesDetailVO.java
@@ -43,4 +43,5 @@
    private Integer useTimes;           // 已用次数
    private Integer status;             // 状态(1:使用中,2:已退款)
    private String orderNumber;             // 支付流水号
    private Long userCouponId;
}
cloud-server-other/src/main/java/com/dsh/other/service/impl/SiteServiceImpl.java
@@ -827,8 +827,8 @@
        if (couponId != null && couponId != 0) {
            if (null != couponId && reservationSite.getPayType() != 3) {
                UserCoupon userCoupon = userCouponClient.queryUserCouponById(new QueryUserCouponByIdAndUserId(reservationSite.getCouponId(), uid));
                if (userCoupon != null && userCoupon.getStatus() == 2) {
                    return ResultUtil.error("优惠券已被核销");
                if (userCoupon == null || userCoupon.getStatus() == null || userCoupon.getStatus() != 1) {
                    return ResultUtil.error("优惠券不可用");
                }
                Coupon coupon = couponClient.queryCouponById(userCoupon.getCouponId());
                long time = coupon.getEndTime().getTime();
@@ -843,7 +843,7 @@
                        return ResultUtil.error("该优惠券无法使用");
                    }
                    money = money.subtract(new BigDecimal(num2)).setScale(2, RoundingMode.HALF_EVEN);
                    money = money.subtract(new BigDecimal(num2)).max(BigDecimal.ZERO).setScale(2, RoundingMode.HALF_EVEN);
                }
                if (userCoupon != null && coupon.getType() == 2) {//代金券
                    JSONObject jsonObject = JSON.parseObject(coupon.getContent());
@@ -851,7 +851,7 @@
                    if (money.compareTo(new BigDecimal(num1)) <= 0) {
                        return ResultUtil.error("该优惠券无法使用");
                    }
                    money = money.subtract(new BigDecimal(num1)).setScale(2, RoundingMode.HALF_EVEN);
                    money = money.subtract(new BigDecimal(num1)).max(BigDecimal.ZERO).setScale(2, RoundingMode.HALF_EVEN);
                }
                userCoupon.setStatus(2);
                userCouponClient.updateUserCoupon(userCoupon);
sql/V20260920__add_coupon_to_ticket_and_huimin_orders.sql
New file
@@ -0,0 +1,8 @@
-- 优惠券使用记录:门票订单(按用户分表)与惠民卡订单。
ALTER TABLE `t_user_points_merchandise` ADD COLUMN `userCouponId` bigint(20) NULL COMMENT '用户优惠券领取记录id';
ALTER TABLE `t_user_points_merchandise1` ADD COLUMN `userCouponId` bigint(20) NULL COMMENT '用户优惠券领取记录id';
ALTER TABLE `t_user_points_merchandise2` ADD COLUMN `userCouponId` bigint(20) NULL COMMENT '用户优惠券领取记录id';
ALTER TABLE `t_user_points_merchandise3` ADD COLUMN `userCouponId` bigint(20) NULL COMMENT '用户优惠券领取记录id';
ALTER TABLE `t_user_points_merchandise4` ADD COLUMN `userCouponId` bigint(20) NULL COMMENT '用户优惠券领取记录id';
ALTER TABLE `t_user_points_merchandise5` ADD COLUMN `userCouponId` bigint(20) NULL COMMENT '用户优惠券领取记录id';
ALTER TABLE `t_pay_huimin` ADD COLUMN `userCouponId` bigint(20) NULL COMMENT '用户优惠券领取记录id';