rk
9 小时以前 77fc61a25c14071584e45731476207959137d6b6
server/dmmall_service/src/main/java/com/doumee/service/business/impl/MemberCouponServiceImpl.java
@@ -15,6 +15,7 @@
import com.doumee.dao.system.model.SystemUser;
import com.doumee.dao.web.dto.CouponDTO;
import com.doumee.dao.web.dto.MemberCouponDTO;
import com.doumee.dao.web.request.CouponNoticeRequest;
import com.doumee.dao.web.request.PayDetailRequest;
import com.doumee.dao.web.response.MemberCouponResponse;
import com.doumee.dao.web.response.goods.OrderGoodsCalculateResponse;
@@ -27,6 +28,7 @@
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.checkerframework.checker.units.qual.A;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@@ -68,41 +70,51 @@
    @Autowired
    private MemberMapper memberMapper;
    @Autowired
    private NoticeMapper noticeMapper;
    @Override
    @Transactional(rollbackFor = {BusinessException.class,Exception.class})
    public    String addBatch(MemberCouponAddDTO memberCoupon){
        checkAddBatchParamValid(memberCoupon);
    public    String addBatch(MemberCouponAddDTO memberCouponAddDTO){
        checkAddBatchParamValid(memberCouponAddDTO);
        int num = 0;
        List<Coupon> couponList = getCouponListByParam(memberCoupon);
        List<Member> memberList = getMemberListByParam(memberCoupon);
        List<Coupon> couponList = getCouponListByParam(memberCouponAddDTO);
        List<Member> memberList = getMemberListByParam(memberCouponAddDTO);
        List<MemberCoupon>  addList = new ArrayList<>();
        int index =1;
        LoginUserInfo loginUserInfo = (LoginUserInfo)SecurityUtils.getSubject().getPrincipal();
        Date now = new Date();
        for(Coupon param  : memberCoupon.getAddCouponList()){
        for(Coupon param  : memberCouponAddDTO.getAddCouponList()){
            Coupon  coupon = getCouponFromListById(param.getId(),couponList);
            if(coupon == null){
                throw  new BusinessException(ResponseStatus.BAD_REQUEST.getCode(),"对不起,第【"+index+"】个优惠券查询无效,请刷新页面重新!");
            }
            for(Member member : memberList){
                MemberCoupon memberCoupon = MemberCoupon.couponToBean(coupon,member,now,Constants.TWO,loginUserInfo);
                for (int i = 0; i < Constants.formatLongNum(param.getNum()); i++) {
                    //满减卷不会生成maxPrice 需要根据优惠券减少金额设置
                    if(Constants.equalsInteger(coupon.getCouponType(),Constants.ZERO)){
                        memberCoupon.setMaxPrice(coupon.getPrice());
                    }
                    //挨个送
                    addList.add(initMemberCouponByParam(coupon,member,loginUserInfo,now));
                    addList.add(memberCoupon);
                }
                num++;
                //优惠券发放通知
                Notice notice = Notice.getNotice(Constants.NoticeType.COUPON,
                        member.getId(),null);
                notice.setContent(notice.getContent().replace("{param}",Constants.getCouponInfo(memberCoupon, (int) Constants.formatLongNum(param.getNum()))));
                noticeMapper.insert(notice);
            }
            index++;
        }
        if(addList.size()>0){
            //批量插入数据
            memberCouponMapper.insert(addList);
        }
        return "操作成功,成功人员数量:"+num+",共发放优惠券数量:"+addList.size();
        return "操作成功,成功人员数量:"+memberList.size()+",共发放优惠券数量:"+addList.size();
    }
/*
    private MemberCoupon initMemberCouponByParam(Coupon coupon, Member member, LoginUserInfo loginUserInfo ,Date now) {
        MemberCoupon insert = new MemberCoupon();
@@ -115,6 +127,7 @@
        insert.setMemberId(member.getId());
        insert.setShopId(coupon.getShopId());
        insert.setType(coupon.getType());
        insert.setCouponType(coupon.getType());
        insert.setLimitPrice(coupon.getLimitPrice());
        insert.setPrice(coupon.getPrice());
        if(Constants.equalsObject(coupon.getUseType(),Constants.ZERO)){
@@ -137,6 +150,7 @@
        insert.setCouponId(coupon.getId());
        return  insert;
    }
*/
    private Coupon getCouponFromListById(Integer id, List<Coupon> couponList) {
        for(Coupon c : couponList){
@@ -176,12 +190,13 @@
        if(list == null || list.size()==0){
            throw new BusinessException(ResponseStatus.BAD_REQUEST.getCode(),"对不起,未查询到有效优惠券数据,请刷新页面重试!");
        }
        return  list;
    }
    private  void checkAddBatchParamValid(MemberCouponAddDTO memberCoupon) {
        if(memberCoupon.getAddType() == null || memberCoupon.getAddCouponList()==null || memberCoupon.getAddCouponList().size()==0){
        if(memberCoupon.getAddType() == null
                || memberCoupon.getAddCouponList()==null
                || memberCoupon.getAddCouponList().size()==0){
            throw new BusinessException(ResponseStatus.BAD_REQUEST);
        }
        if(Constants.equalsObject(memberCoupon.getAddType(),Constants.ZERO)){
@@ -194,7 +209,7 @@
            if( StringUtils.isBlank(memberCoupon.getAddMemberPhones())){
                throw new BusinessException(ResponseStatus.BAD_REQUEST);
            }
            String[] ss =memberCoupon.getAddMemberPhones().split("\n");
            String[] ss =memberCoupon.getAddMemberPhones().replace(" ","").split("\n");
            if(ss == null ||ss.length==0){
                throw new BusinessException(ResponseStatus.BAD_REQUEST);
            }
@@ -316,6 +331,7 @@
        MPJLambdaWrapper<MemberCoupon> queryWrapper = new MPJLambdaWrapper<>();
        Utils.MP.blankToNull(pageWrap.getModel());
        queryWrapper.selectAll(MemberCoupon.class);
        queryWrapper.selectAs(Member::getPhone,MemberCoupon::getMemberPhone);
        queryWrapper.selectAs(Member::getNickname,MemberCoupon::getNikeName);
        queryWrapper.selectAs(Goodsorder::getCode,MemberCoupon::getOrderCode);
        queryWrapper.selectAs(Goodsorder::getCouponPrice,MemberCoupon::getCouponPrice);//优惠金额
@@ -324,13 +340,16 @@
        queryWrapper.leftJoin(Goodsorder.class,Goodsorder::getId,MemberCoupon::getOrderId);
        queryWrapper.leftJoin(SystemUser.class,SystemUser::getId,MemberCoupon::getCreator);
        queryWrapper.eq(MemberCoupon::getIsdeleted, Constants.ZERO);
        if(pageWrap.getModel().getStatus()!=null && pageWrap.getModel().getStatus()!=2){
            queryWrapper.eq(pageWrap.getModel().getStatus()!=null,MemberCoupon::getStatus, pageWrap.getModel().getStatus());
        } else if (pageWrap.getModel().getStatus()!=null && pageWrap.getModel().getStatus()==2) {
            //查询已过期(未使用,切已过了使用期限)
            queryWrapper.eq( MemberCoupon::getStatus, Constants.ZERO);
            queryWrapper.lt( MemberCoupon::getEndDate, new Date());
        if(Constants.equalsInteger(pageWrap.getModel().getStatus(),0)&&pageWrap.getModel().getIsexpire()!=null && pageWrap.getModel().getIsexpire()== 0){
            queryWrapper.gt( MemberCoupon::getEndDate, new Date());
        } else if (Constants.equalsInteger(pageWrap.getModel().getStatus(),0)&&pageWrap.getModel().getIsexpire()!=null && pageWrap.getModel().getIsexpire()== 1) {
            queryWrapper.le( MemberCoupon::getEndDate, new Date());
        }
        queryWrapper.in(pageWrap.getModel().getMethodList()!=null,MemberCoupon::getGetMethod, pageWrap.getModel().getMethodList());
        queryWrapper.eq(pageWrap.getModel().getStatus()!=null,MemberCoupon::getStatus, pageWrap.getModel().getStatus());
        queryWrapper.eq(pageWrap.getModel().getCouponType()!=null,MemberCoupon::getCouponType, pageWrap.getModel().getCouponType());
        queryWrapper.eq(pageWrap.getModel().getCouponId()!=null,MemberCoupon::getCouponId, pageWrap.getModel().getCouponId());
        queryWrapper.like(pageWrap.getModel().getName()!=null,MemberCoupon::getName, pageWrap.getModel().getName());
        queryWrapper.eq(pageWrap.getModel().getOrderCode()!=null,Goodsorder::getCode, pageWrap.getModel().getOrderCode());
        queryWrapper.eq(pageWrap.getModel().getGetMethod()!=null,MemberCoupon::getGetMethod, pageWrap.getModel().getGetMethod());
        queryWrapper.and(StringUtils.isNotBlank(pageWrap.getModel().getNikeName()),ms -> ms.like( Member::getNickname,  pageWrap.getModel().getNikeName()).
@@ -340,11 +359,14 @@
        IPage<MemberCoupon> result = memberCouponJoinMapper.selectJoinPage(page, MemberCoupon.class, queryWrapper);
        if(result!=null && result.getRecords()!=null){
            for(MemberCoupon model :result.getRecords()){
                model.setNikeName(StringUtils.defaultString(model.getNikeName(),"")+" "+StringUtils.defaultString(model.getMemberPhone(),""));
                if(Constants.equalsInteger(model.getStatus(),Constants.ZERO)
                        && model.getEndDate()!=null
                        && model.getEndDate().before(new Date())){
                    //已过期
                    model.setStatus(Constants.TWO);
                    model.setIsexpire(Constants.ONE);
                }else if(Constants.equalsInteger(model.getStatus(),Constants.ZERO)){
                    model.setIsexpire(Constants.ZERO);
                }
            }
        }
@@ -378,7 +400,7 @@
                .apply(Objects.nonNull(status)&&Constants.equalsInteger(status,Constants.TWO),"m.STATUS = 0 and  m.END_DATE < now() " )
                .eq("TYPE",couponType)
                .apply(!Objects.isNull(price)," m.LIMIT_PRICE >= "+price+" ")
                .apply("   now() between m.START_DATE and m.END_DATE ")
//                .apply("   now() between m.START_DATE and m.END_DATE ")
                .orderByDesc(" m.PRICE ")
        );
        return page;
@@ -518,10 +540,7 @@
        memberCoupon.setBackIntegral(BigDecimal.ZERO);
        memberCoupon.setName(coupon.getName());
        memberCouponMapper.insert(memberCoupon);
        //TODO 添加积分变动记录
        //更新用户积分
        memberMapper.subtractIntegral(memberId,memberCoupon.getIntegral());
    }
@@ -537,11 +556,12 @@
                .in(GoodsSku::getId,requestList.stream().map(i->i.getGoodsSkuId()).collect(Collectors.toList()))
        );
        if(CollectionUtils.isEmpty(goodsSkuList)||!Constants.equalsInteger(goodsSkuList.size(),requestList.size())){
            throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),"商品SKU信息错误,请刷新重试");
            throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),"商品SKU信息已失效,请刷新重试");
        }
        //查询商品列表
        List<Goods> goodsList = goodsMapper.selectJoinList(Goods.class,
                new MPJLambdaWrapper<Goods>()
                        .selectAll(Goods.class)
                        .selectAs(GoodsSku::getPrice,Goods::getSkuPrice)
                        .selectAs(GoodsSku::getId,Goods::getSkuId)
                        .leftJoin(GoodsSku.class,GoodsSku::getGoodsId,Goods::getId)
@@ -564,28 +584,37 @@
        List<MemberCoupon> allCoupon =  memberCouponMapper.selectList(new QueryWrapper<MemberCoupon>().lambda()
                        .eq(MemberCoupon::getIsdeleted,Constants.ZERO)
                        .eq(MemberCoupon::getStatus,Constants.ZERO)
                        .eq(MemberCoupon::getMemberId,memberId)
                        .apply("  LIMIT_PRICE <= " + totalAmount)
                        .apply("  now() between START_DATE and  END_DATE "));
                        .apply("  now() between START_DATE and  END_DATE ")
                        .orderByDesc(MemberCoupon::getMaxPrice)
                        .orderByAsc(MemberCoupon::getEndDate)
        )
                ;
        if(CollectionUtils.isNotEmpty(allCoupon)){
            for (MemberCoupon memberCoupon:allCoupon) {
                //适用类型:0=全场;1=品类;2=指定商品
                if(this.calculateCouponRata(memberCoupon,goodsCalculateList,totalAmount).compareTo(memberCoupon.getPrice())<=Constants.ZERO){
                    continue;
                }
                memberCouponList.add(memberCoupon);
                /*//适用类型:0=全场;1=品类;2=指定商品
                 if(Constants.equalsInteger(memberCoupon.getApplyType(),Constants.ZERO)){
                     memberCoupon.setValidAmount(memberCoupon.getPrice());
                     memberCoupon.setValidAmount(memberCoupon.getMaxPrice());
                     memberCouponList.add(memberCoupon);
                 }else{
                     List<String> applyIdList = Arrays.asList(memberCoupon.getApplyIds().split(","));
                     //获取有效可以使用优惠券的数据
                     isVaildUse(applyIdList,goodsCalculateList,
                             Constants.equalsInteger(memberCoupon.getApplyType(),Constants.ONE)?Constants.ONE:Constants.ZERO);
                     isVaildUse(applyIdList,goodsCalculateList,memberCoupon.getApplyType());
                     BigDecimal skuAmount = goodsCalculateList.stream().filter(i->i.getUseCoupon()).map(i->i.getSkuAmount()).reduce(BigDecimal.ZERO,BigDecimal::add);
                     if(skuAmount.compareTo(memberCoupon.getLimitPrice())>=Constants.ZERO){
                         //根据金额计算实际折扣金额
                         BigDecimal couponPrice = skuAmount.multiply(memberCoupon.getPrice()).divide(new BigDecimal("100"),2, RoundingMode.HALF_UP);
                         //根据金额计算实际折扣金额  PRICE 存储折扣值  例如 5折 存储值 5
                         BigDecimal couponPrice = skuAmount.multiply(memberCoupon.getPrice()).divide(new BigDecimal("10"),2, RoundingMode.HALF_UP);
                         //折扣金额大于最大可折扣金额  则使用最大可折扣金额
                         memberCoupon.setValidAmount(couponPrice.compareTo(memberCoupon.getMaxPrice())>Constants.ZERO?memberCoupon.getMaxPrice():couponPrice);
                         memberCouponList.add(memberCoupon);
                     }
                 }
                 }*/
            }
        }
        // 使用 Stream 排序  reversed() 表示倒序
@@ -613,7 +642,7 @@
                .in(GoodsSku::getId,requestList.stream().map(i->i.getGoodsSkuId()).collect(Collectors.toList()))
        );
        if(CollectionUtils.isEmpty(goodsSkuList)||!Constants.equalsInteger(goodsSkuList.size(),requestList.size())){
            throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),"商品SKU信息错误,请刷新重试");
            throw new BusinessException(ResponseStatus.NOT_ALLOWED.getCode(),"商品SKU信息已失效,请刷新重试");
        }
        //查询商品列表
        List<Goods> goodsList = goodsMapper.selectJoinList(Goods.class,
@@ -657,20 +686,16 @@
    }
    /**
     * 计算当前已选择优惠券每个商品占比金额
     * 计算优惠券每个商品占比金额
     * @param coupon 优惠券信息
     * @param goodsCalculateList 商品集合
     * @param totalAmount 订单总金额
     * @return 可以使用优惠券的商品总金额
     */
    public void  calculateCouponRata(MemberCoupon coupon,List<OrderGoodsCalculateResponse> goodsCalculateList,BigDecimal totalAmount){
    public BigDecimal calculateCouponRata(MemberCoupon coupon,List<OrderGoodsCalculateResponse> goodsCalculateList,BigDecimal totalAmount){
        //总余额
        BigDecimal validAmount = coupon.getValidAmount();
        BigDecimal validAmount = coupon.getMaxPrice();
        //剩余可分配金额
        BigDecimal surplusValidAmount = validAmount;
        //已用占比比例值
@@ -678,11 +703,23 @@
        //根据优惠券类型 计算可以使用优惠券的商品信息 适用类型:0=全场;1=品类;2=指定商品
        if(!Constants.equalsInteger(coupon.getApplyType(),Constants.ZERO)){
            List<String> applyIdList = Arrays.asList(coupon.getApplyIds().split(","));
            isVaildUse(applyIdList,goodsCalculateList,
                    Constants.equalsInteger(coupon.getApplyType(),Constants.ONE)?Constants.ONE:Constants.ZERO);
            isVaildUse(applyIdList,goodsCalculateList,coupon.getApplyType());
        }else{
            isVaildUse(null,goodsCalculateList,coupon.getApplyType());
        }
        //使用了优惠券的商品数量
        Integer countCouponNum = goodsCalculateList.stream().filter(i->i.getUseCoupon()).collect(Collectors.toList()).size();
        //使用优惠券的总金额
        BigDecimal useCouponPrice = goodsCalculateList.stream().filter(i->i.getUseCoupon())
                .map(i->i.getSkuAmount()).reduce(BigDecimal.ZERO,BigDecimal::add);
        if(Constants.equalsInteger(coupon.getCouponType(),Constants.ONE)){
            //最大可优惠金额
            BigDecimal couponAmount = useCouponPrice.multiply(coupon.getPrice()).divide(new BigDecimal("10"),2,BigDecimal.ROUND_DOWN);
            if(couponAmount.compareTo(validAmount)<=Constants.ZERO){
                validAmount = couponAmount;
                surplusValidAmount = validAmount;
            }
        }
        Integer useCouponNum = Constants.ZERO;
        for (int i = 0; i < goodsCalculateList.size(); i++) {
            if(!goodsCalculateList.get(i).getUseCoupon()){
@@ -692,6 +729,7 @@
            if(Constants.equalsInteger(useCouponNum+1,countCouponNum)){
                goodsCalculateList.get(i).setOrderCouponRata(new BigDecimal("1").subtract(rata));
                goodsCalculateList.get(i).setCouponDeductCash(surplusValidAmount);
                surplusValidAmount = BigDecimal.ZERO;
                break;
            }
            goodsCalculateList.get(i).setOrderCouponRata(goodsCalculateList.get(i).getSkuAmount().divide(totalAmount,2,BigDecimal.ROUND_DOWN));
@@ -700,6 +738,8 @@
            rata = rata.add(goodsCalculateList.get(i).getOrderCouponRata());
            useCouponNum = useCouponNum + 1;
        }
        coupon.setValidAmount(validAmount.subtract(surplusValidAmount));
        return useCouponPrice;
    }
@@ -710,14 +750,24 @@
     * 判断是否可以有效使用
     * @param idList
     * @param goodsList
     * @param vaildType 0=商品;1=品类
     * @param vaildType 0=全场;1=品类;2=指定商品
     * @return
     */
    public void isVaildUse(List<String> idList,List<OrderGoodsCalculateResponse> goodsList,Integer vaildType){
        for (OrderGoodsCalculateResponse response:goodsList) {
            response.setUseCoupon(idList.contains(Constants.equalsInteger(vaildType,Constants.ZERO)?response.getId().toString():response.getCategoryId().toString())?true:false);
        if(Constants.equalsInteger(vaildType,Constants.ZERO)){
            for (OrderGoodsCalculateResponse response:goodsList) {
                response.setUseCoupon(true);
            }
        }else{
            for (OrderGoodsCalculateResponse response:goodsList) {
                response.setUseCoupon(idList.contains(Constants.equalsInteger(vaildType,Constants.TWO)?response.getId().toString():response.getCategoryId().toString())?true:false);
            }
        }
    }
//    public Set<Integer> isVaildUse(List<String> idList,List<OrderGoodsCalculateResponse> goodsList,Integer vaildType){
//        List<OrderGoodsCalculateResponse> resultList = new ArrayList<>();
//        for (String id:idList) {
@@ -732,10 +782,60 @@
//        }
//        return new HashSet<>();
//    }
    @Override
    @Transactional(rollbackFor = {Exception.class})
    public void notifyExpiredCoupon(Integer days) {
        if (days == null || days <= 0) {
            days = 3; // 默认提前 3 天通知
        }
        String afterDate = DateUtil.afterDateToStr(days);
        // 查询即将过期的优惠券(未使用且在目标日期范围内过期)
        List<MemberCoupon> expiredCoupons = memberCouponMapper.selectList(
            new QueryWrapper<MemberCoupon>().lambda()
                .eq(MemberCoupon::getIsdeleted, Constants.ZERO)
                .eq(MemberCoupon::getStatus, Constants.ZERO) // 未使用
                .eq(MemberCoupon::getNoticeStatus,Constants.ZERO)// 未通知数据
                .ge(MemberCoupon::getEndDate, DateUtil.getCurrDateTime()) // 大于等于开始时间
                .lt(MemberCoupon::getEndDate, (afterDate+" 23:59:59") )  // 小于结束时间
        );
        if (CollectionUtils.isEmpty(expiredCoupons)) {
            return;
        }
        // 按用户分组统计
        Map<Integer, List<MemberCoupon>> memberCouponMap = expiredCoupons.stream()
                .collect(Collectors.groupingBy(MemberCoupon::getMemberId));
        // 遍历每个用户的优惠券发送通知
        for (Map.Entry<Integer, List<MemberCoupon>> entry : memberCouponMap.entrySet()) {
            Integer memberId = entry.getKey();
            List<MemberCoupon> coupons = entry.getValue();
            if (CollectionUtils.isEmpty(coupons)) {
                continue;
            }
            // 查询用户信息
            Member member = memberMapper.selectById(memberId);
            if (member == null || member.getIsdeleted() == Constants.ONE) {
                continue;
            }
            // 统计优惠券数量和类型
            long count = coupons.size();
            List<Integer> couponIds = coupons.stream().map(MemberCoupon::getId).collect(Collectors.toList());
            //发送站内信 优惠券即将过期
            Notice notice = Notice.getNotice(
                    Constants.NoticeType.EXPIRE_COUPON,
                    member.getId(),
                    null
            );
            notice.setContent(notice.getContent().replace("{param}",Long.toString(count)).replace("{param1}",afterDate));
            noticeMapper.insert(notice);
            memberCouponMapper.update(new UpdateWrapper<MemberCoupon>().lambda()
                    .set(MemberCoupon::getNoticeStatus,Constants.ONE)
                    .set(MemberCoupon::getNoticeTime,DateUtil.getCurrDateTime())
                    .in(MemberCoupon::getId,couponIds)
            );
        }
    }
}