小程序智能聊天机器人(二)

背景

接上篇小程序智能聊天机器人(一)
无论何种程序,在我们没有其他收益来源时,用户付费,是让我们回笼成本的重要渠道之一,所以在一个项目中,会员支付就比较重要了,接下来我们继续进行。

会员套餐设置

所谓会员,就要有不同的会员套餐,就像我们用QQ,各类影视平台一样,有一个月,两个月,三个月,等等。所以我们也先来搞个套餐。我们先来建个表:

CREATE TABLE `t_vip_package` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键',
  `vip_name` varchar(100) DEFAULT NULL COMMENT '会员名称',
  `vip_description` varchar(1000) DEFAULT NULL COMMENT '会员描述',
  `original_price` decimal(10,2) DEFAULT NULL COMMENT '原价',
  `price` decimal(10,2) DEFAULT NULL COMMENT '价格',
  `show_status` char(1) DEFAULT NULL COMMENT '显示状态:0隐藏 1显示',
  `vip_type` char(1) DEFAULT NULL COMMENT '会员类型:0天 1月 2年 3永久',
  `duration` int(11) DEFAULT NULL COMMENT '时长仅在永久时可为空',
  `day_times` bigint(20) DEFAULT NULL COMMENT '每日提问数',
  `choose_status` varchar(100) DEFAULT NULL COMMENT '默认选中:0未选中 1选中',
  `create_time` datetime DEFAULT NULL COMMENT '创建时间',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='会员套餐';

表创建完了,自己加几个套餐数据进去用来测试

获取套餐

我们开放接口给小程序端获取所有的套餐列表:

	@PostMapping("getAllVipPackages")
    public AjaxResult getAllVipPackages(){
    
    
        startPage();
        List<VipPackage> vipPackages = vipPackageService.list(new QueryWrapper<VipPackage>().eq("show_status", "1"));
        vipPackages.forEach(vipPackage -> {
    
    //这里我们计算一下每天多少钱,用于前台展示
            vipPackage.setDayPrice(new BigDecimal("0"));
            if(!"3".equals(vipPackage.getVipType())){
    
    
                String vipType = vipPackage.getVipType();
                BigDecimal o = new BigDecimal("1");
                if ("1".equals(vipType)){
    
    
                    o = new BigDecimal("30");
                }
                if ("2".equals(vipType)){
    
    
                    o = new BigDecimal("365");
                }
                BigDecimal totalDay = new BigDecimal(vipPackage.getDuration()).multiply(o);
                vipPackage.setDayPrice(vipPackage.getPrice().divide(totalDay, BigDecimal.ROUND_CEILING));
            }
        });

        return AjaxResult.success(getDataTable(vipPackages));
    }

前台效果是这样:
在这里插入图片描述

订单创建

小程序端选中套餐之后,我们后台提供一个订单生成接口,存储一些基本信息,然后把订单主键返回给前端。这里我们也可以直接向微信官方发起支付申请,因为小程序内只能进行微信支付,因为我的项目不仅在小程序端,所以进行了这一步操作。

    @PostMapping("createOrder")
    @RestApi
    public AjaxResult createOrder(Long vipId){
    
    
        Long userId = JwtTokenUtil.getUserId;

        VipPackage vipPackage = vipPackageService.getById(vipId);
        if (StringUtils.isNull(vipPackage)){
    
    
            return AjaxResult.error("该套餐不存在");
        }
        
        Order order = new Order();
        order.setVipName("充值"+vipPackage.getVipName());
        order.setPrice(vipPackage.getPrice());
        order.setVipId(vipId);
        order.setUserId(userId);
        order.setDuration(vipPackage.getDuration());
        order.setUnits(vipPackage.getVipType());
        order.setIsAll("3".equals(vipPackage.getVipType()) ? "1" : "0");
        orderService.save(order);
        Map<String, Long> retObj = new HashMap<>();
        retObj.put("orderId", order.getId());
        return AjaxResult.success("订单创建成功!", retObj);
    }

支付订单申请

前端拿到我们的主键之后,可申请发起支付,这个时候,我们再向微信发起支付申请:

	@PostMapping("/toPay")
    @ApiOperation("支付订单")
    @RestApi
    public AjaxResult toPay(Long orderId, String payType){
    
    
        Order order=orderService.getById(orderId);
        if (StringUtils.isNull(order)){
    
    
            return AjaxResult.error("订单不存在");
        }
        if (order.getStatus().equals("1")){
    
    
            return AjaxResult.error("该订单已支付");
        }
        order.setOrderNo(RandomUtil.randomNumbers(13));
        order.setPayType(payType);
        orderService.updateById(order);
        switch (payType){
    
    
            case "1": //支付宝
                return aliPayConfig.AliPay(order);
            case "2"://微信支付,参考官方api进行一些参数配置就好。
                return wxPayConfig.WxPay(order);
            default:
                return AjaxResult.error("请选择支付方式");
        }
    }

把官方的数据,返回给前端,前端就可以拉起支付了。

支付回调

用户支付完成之后,微信官方会给我们回调通知,也就是告诉我们支付的结果,我们需要在拿到成功支付结果后,再更新一下用户的会员权益

 public String wxPayNotify(HttpServletRequest request) {
    
    
        String xmlMsg = HttpKit.readData(request);
        log.info("微信支付通知=" + xmlMsg);
        Map<String, String> params = WxPayKit.xmlToMap(xmlMsg);

        String returnCode = params.get("return_code");
        //获取创建时候的 商户订单号(唯一就行)
        String orderNo = params.get("out_trade_no");
        Map<String, String> xml;
        // 注意此处签名方式需与统一下单的签名类型一致
//		if (WxPayKit.verifyNotify(params, "初始密钥", SignType.HMACSHA256)) {
    
    
        if (WxPayKit.verifyNotify(params,PaySetConfig.KEY, SignType.HMACSHA256)) {
    
    
            if (WxPayKit.codeIsOk(returnCode)) {
    
    
                // 注意重复通知的情况,同一订单号可能收到多次通知,请注意一定先判断订单状态
                Order order = orderService.getOne(new QueryWrapper<Order>().lambda().eq(Order::getOrderNo, orderNo));
                if (order.getStatus().equals("1")) {
    
    
                    xml = new HashMap<>(2);
                    xml.put("return_code", "-1");
                    xml.put("return_msg", "订单状态失效或已支付,请重新下单");
                    return WxPayKit.toXml(xml);
                }
                // 更新订单信息
                aliPayConfig.updateOrder(order);
                // 发送通知等
                xml = new HashMap<>(2);
                xml.put("return_code", "200");
                xml.put("return_msg", "回调成功");
                return WxPayKit.toXml(xml);
            }
        }
        return null;
    }

我们先给官方回复个消息,告诉他,我收到通知了!

更新用户权益

接下来更新下用户权益,整个流程就完成了:

/** 修改订单及业务逻辑*/
    public void updateOrder(Order order){
    
    
        order.setStatus("1");

//        AppUser appUser=appUserService.getOne(new QueryWrapper<AppUser>().eq("userName", order.getUserId()));
        AppUser appUser = appUserService.getById(order.getUserId());
        if(StringUtils.isNull(appUser) || appUser.getUserType().equals("3")){
    
    
            orderService.updateById(order);
            return;
        }
        VipPackage vipPackage = vipPackageService.getById(order.getVipId());
        appUser.setUserType("1");//会员
        appUser.setDayLimitTimes(vipPackage.getDayTimes());
        //充值套餐
        if (vipPackage.getVipType().equals("3")) {
    
    //是否永久
            appUser.setUserType("3");//永久
        } else {
    
    
            //过期时间 TODO
            //用户过期时间
            appUser.setVipExpTime(getUserExpTime(StringUtils.isNull(appUser.getVipExpTime()) ? new Date(): appUser.getVipExpTime(),vipPackage.getDuration(), vipPackage.getVipType()));
            //该会员过期时间
            order.setExpTime(getUserExpTime(new Date(), vipPackage.getDuration(), vipPackage.getVipType()));
            //其他会员顺延
            setOtherVipExpTime(appUser.getId(), order.getId(), vipPackage.getDuration(), vipPackage.getVipType());
        }
        if(StringUtils.isNull(appUser.getVipExpTime()) || appUser.getVipExpTime().before(new Date())){
    
    //处理下生效时间,若是已失效,则从当前开始
            appUser.setVipEffTime(new Date());
        }
        orderService.updateById(order);
        appUserService.updateById(appUser);
//        order.set(getUserExpTime();
//        AsyncManager.me().execute(MyMessageFactory.socketSendToAll(appUser,"expTime"));
    }

总结

文章内我对整个流程代码没有做细节的讲述,我觉得开发主要是你针对项目的业务场景,有个大概的流程框架,这个东西具备之后,你可以慢慢往里面填写你的业务代码,反正我每次都是先这么干的,先评估整个项目大概需要后端做哪些接口,然后再去把接口中的业务逻辑慢慢填充起来。重要的就是思路要清晰,每一步要做什么先搞清楚!

猜你喜欢

转载自blog.csdn.net/lovejiwei/article/details/129819472