尚医通(二十四)微信退款(取消预约功能)

一、取消预约

1、需求描述

取消订单分两种情况:
(1)未支付取消订单,直接通知医院更新取消预约状态
(2)已支付取消订单,先退款给用户,然后通知医院更新取消预约状态

2、开发取消预约接口

参考文档:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=9_4
该接口需要使用证书,详情参考文档并下载证书
(1)配置证书
请下载的证书放在service-order模块/resources/cert文件夹下
在这里插入图片描述
记得修改HttpClient里面的方法,改成证书所放的路径
在这里插入图片描述

(2)添加退款记录
添加RefundInfoMapper

public interface RefundInfoMapper extends BaseMapper<RefundInfo> {
}

添加RefundInfoService方法和实现

//RefundInfoService
public interface RefundInfoService extends IService<RefundInfo> {
    RefundInfo saveRefundInfo(PaymentInfo paymentInfo);
}

//RefundInfoServiceImpl
@Service
public class RefundInfoServiceImpl  extends ServiceImpl<RefundInfoMapper, RefundInfo> implements RefundInfoService {

    @Override
    public RefundInfo saveRefundInfo(PaymentInfo paymentInfo) {
        Long orderId = paymentInfo.getOrderId();
        QueryWrapper<RefundInfo> queryWrapper=new QueryWrapper<RefundInfo>();
        queryWrapper.eq("order_id",orderId);
        RefundInfo refundInfo1 = baseMapper.selectOne(queryWrapper);
        if(refundInfo1 != null){
            return refundInfo1;
        }

        RefundInfo refundInfo=new RefundInfo();
        refundInfo.setOutTradeNo(paymentInfo.getOutTradeNo());
        refundInfo.setOrderId(paymentInfo.getOrderId());
        refundInfo.setPaymentType(PaymentTypeEnum.WEIXIN.getStatus());
        refundInfo.setTotalAmount(paymentInfo.getTotalAmount());
        refundInfo.setSubject("想退款...");
        refundInfo.setRefundStatus(RefundStatusEnum.UNREFUND.getStatus());
        baseMapper.insert(refundInfo);
        return refundInfo;
    }
}

(3)添加微信退款方法
在WeixinService添加方法

    /***
     * 退款
     * @param orderId
     * @return
     */
    boolean refund(Long orderId);

在WeixinServiceImpl添加实现

    @Override
    public boolean refund(Long orderId) {

        QueryWrapper<PaymentInfo> queryWrapper=new QueryWrapper<PaymentInfo>();
        queryWrapper.eq("order_id",orderId);
        PaymentInfo paymentInfo = paymentService.getOne(queryWrapper);
        RefundInfo refundInfo=refundInfoService.saveRefundInfo(paymentInfo);
        //已退款
        if(refundInfo.getRefundStatus().intValue() == RefundStatusEnum.REFUND.getStatus().intValue()){
            return true;
        }
        //执行微信退款
        HttpClient httpClient=new HttpClient("https://api.mch.weixin.qq.com/secapi/pay/refund");

        Map<String,String> paramMap = new HashMap<>(8);

        paramMap.put("appid",weiPayProperties.getAppid());       //公众账号ID
        paramMap.put("mch_id",weiPayProperties.getPartner());   //商户编号
        paramMap.put("nonce_str",WXPayUtil.generateNonceStr());
        paramMap.put("transaction_id",paymentInfo.getTradeNo()); //微信支付订单号

        paramMap.put("out_trade_no",paymentInfo.getOutTradeNo()); //商户订单编号
        paramMap.put("out_refund_no","tk"+paymentInfo.getOutTradeNo()); //商户退款单号
        //       paramMap.put("total_fee",paymentInfoQuery.getTotalAmount().multiply(new BigDecimal("100")).longValue()+"");
        //       paramMap.put("refund_fee",paymentInfoQuery.getTotalAmount().multiply(new BigDecimal("100")).longValue()+"");

        paramMap.put("total_fee","1");
        paramMap.put("refund_fee","1");
        try {
            String paramXml = WXPayUtil.generateSignedXml(paramMap,weiPayProperties.getPartnerkey());
            httpClient.setXmlParam(paramXml);
            httpClient.setHttps(true);
            httpClient.setCert(true); //设置证书支持
            httpClient.setCertPassword(weiPayProperties.getPartner()); //设置证书密码
            httpClient.post();

            String content = httpClient.getContent();
            Map<String, String> resultMap = WXPayUtil.xmlToMap(content);
            if("SUCCESS".equals(resultMap.get("result_code"))){ //微信退款成功
                refundInfo.setTradeNo(resultMap.get("refund_id"));//微信退款交易号
                refundInfo.setRefundStatus(RefundStatusEnum.REFUND.getStatus());
                refundInfo.setCallbackTime(new Date());
                refundInfo.setCallbackContent(JSONObject.toJSONString(resultMap));
                refundInfoService.updateById(refundInfo);
                return true;

            }
            return  false;

        }catch (Exception ex){
            ex.printStackTrace();
        }

        return false;
    }

(4)完成取消预约方法
在OrderService添加和实现

    /**
     * 取消订单
     * @param orderId
     */
    void cancelOrder(Long orderId);

   //实现方法
    @Override
    public void cancelOrder(Long orderId) {
        OrderInfo orderInfo = baseMapper.selectById(orderId);
        DateTime quitTime = new DateTime(orderInfo.getQuitTime());
        //1.确定当前取消预约的时间 和 挂号订单的取消预约截止时间 对比, 当前时间是否已经超过了 挂号订单的取消预约截止时间
        //1.1 如果超过了,直接抛出异常,不让用户取消
        if(quitTime.isBeforeNow()){
            throw  new YyghException(20001,"超过了退号的截止时间");
        }

        Map<String,Object>  hospitalParamMap=new HashMap<String,Object>();
        hospitalParamMap.put("hoscode",orderInfo.getHoscode());
        hospitalParamMap.put("hosRecordId",orderInfo.getHosRecordId());


        //2.从平台请求第三方医院,通知第三方医院,该用户已取消
        JSONObject jsonObject = HttpRequestHelper.sendRequest(hospitalParamMap, "http://localhost:9998/order/updateCancelStatus");
        //2.1 第三方医院如果不同意取消:抛出异常,不能取消
        if(jsonObject == null || jsonObject.getIntValue("code") != 200){
            throw  new YyghException(20001,"取消失败");
        }
        //3.判断用户是否对当前挂号订单是否已支付
        if(orderInfo.getOrderStatus() == OrderStatusEnum.PAID.getStatus()){
            //3.1.如果已支付,退款
            boolean flag= weixinService.refund(orderId);
            if(!flag){
                throw new YyghException(20001,"退款失败");
            }
        }

        //无论用户是否进了支付

        //4.更新订单的订单状态 及 支付记录表的支付状态
        orderInfo.setOrderStatus(OrderStatusEnum.CANCLE.getStatus());
        baseMapper.updateById(orderInfo);

        UpdateWrapper<PaymentInfo> updateWrapper=new UpdateWrapper<PaymentInfo>();
        updateWrapper.eq("order_id",orderInfo.getId());
        updateWrapper.set("payment_status", PaymentStatusEnum.REFUND.getStatus());
        paymentService.update(updateWrapper);

        //5.更新医生的剩余可预约数信息

        OrderMqVo orderMqVo=new OrderMqVo();
        orderMqVo.setScheduleId(orderInfo.getScheduleId());
        SmsVo msmVo=new SmsVo();
        msmVo.setPhone(orderInfo.getPatientPhone());
        msmVo.setTemplateCode("xxxx.....");
        msmVo.setParam(null);
        orderMqVo.setSmsVo(msmVo);
        //6.给就诊人发送短信提示:
        rabbitService.sendMessage(MqConst.EXCHANGE_DIRECT_ORDER,MqConst.ROUTING_ORDER,orderMqVo);
    }

(5)在WeixinService添加方法
在OrderInfoController添加方法

    @GetMapping("/cancel/{orderId}")
    public R cancelOrder(@PathVariable Long orderId){
        orderInfoService.cancelOrder(orderId);
        return R.ok();
    }

(6)修改监听器方法
service-hosp
修改OrderMqListener类

@Component
public class OrderMqListener {

    @Autowired
    private ScheduleService scheduleService;
    @Autowired
    private RabbitService rabbitService;

    @RabbitListener(bindings = {
            @QueueBinding(
                    value =@Queue(name = MqConst.QUEUE_ORDER,durable = "true"),//创建队列
                    exchange = @Exchange(name = MqConst.EXCHANGE_DIRECT_ORDER), //创建交换机
                    key=MqConst.ROUTING_ORDER
            )
    })
    //确认挂号:走该方法 -n
    //取消预约:走方法 : +1
    public void consume(OrderMqVo orderMqVo, Message message, Channel channel){
        String scheduleId = orderMqVo.getScheduleId();
        Integer availableNumber = orderMqVo.getAvailableNumber();
        SmsVo msmVo = orderMqVo.getSmsVo();
        if(availableNumber != null){
            boolean flag= scheduleService.updateAvailableNumber(scheduleId,availableNumber);

        }else{
            scheduleService.cancelSchedule(scheduleId);
        }

        if(msmVo != null){
            rabbitService.sendMessage(MqConst.EXCHANGE_DIRECT_SMS,MqConst.ROUTING_SMS_ITEM,msmVo);
        }


    }
}

取消预约了,把可预约人数加回去

    void cancelSchedule(String scheduleId);

    @Override
    public void cancelSchedule(String scheduleId) {
        Schedule schedule=scheduleRepository.findByHosScheduleId(scheduleId);
        schedule.setAvailableNumber(schedule.getAvailableNumber()+1);
        scheduleRepository.save(schedule);
    }
@Repository
public interface ScheduleRepository extends MongoRepository<Schedule,String> {
    Schedule findByHosScheduleId(String scheduleId);
}

3、开发微信退款前端
(1)添加wx.js添加方法

cancelOrder(orderId) {
  return request({
      url: `/api/order/orderInfo/cancel/${orderId}`,
      method: 'get'
  })
},

(2)修改show.vue组件

      //取消预约方法
      cancelOrder() {
        this.$confirm('确定取消预约吗, 是否继续?', '提示', {
          confirmButtonText: '确定',
          cancelButtonText: '取消',
          type: 'warning'
        }).then(() => {
          wxApi.cancelOrder(this.orderId).then(resp=>{
            this.$message.success("取消成功")
            this.init()
          })
        }).catch(() => {
          this.$message({
            type: 'info',
            message: '已取消操作'
          });          
        });
      },


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Knight_AL

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值