目录
- 一、取消预约
- 1、需求描述
- 2、开发取消预约接口
一、取消预约
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: '已取消操作'
});
});
},