尚品汇-订单拆单、支付宝关闭交易、关闭过期订单整合(五十)
目录:
(1)拆单接口
(2)取消订单业务补充关闭支付记录
(3)支付宝关闭交易
(4)查询支付交易记录
(5)PaymentFeignClient 远程接口
(6)整合关闭过期订单
(1)拆单接口
仓库表:不是同一个仓库
在service_order模块
订单实现拆单接口OrderService
List<OrderInfo> orderSplit(Long orderId, String wareSkuMap);
拆单接口实现类OrderServiceImpl
@Override
@Transactional
public List<OrderInfo> orderSplit(Long orderId, String wareSkuMap) {
ArrayList<OrderInfo> orderInfoArrayList = new ArrayList<>();
/*
1. 先获取到原始订单 107
2. 将wareSkuMap 转换为我们能操作的对象 [{"wareId":"1","skuIds":["2","10"]},{"wareId":"2","skuIds":["3"]}]
方案一:class Param{
private String wareId;
private List<String> skuIds;
}
方案二:看做一个Map mpa.put("wareId",value); map.put("skuIds",value)
3. 创建一个新的子订单 108 109 。。。
4. 给子订单赋值
5. 保存子订单到数据库
6. 修改原始订单的状态
7. 测试
*/
//获取父订单
OrderInfo orderInfoOrigin = getOrderInfoById(orderId);
List<Map> maps = JSON.parseArray(wareSkuMap, Map.class);
if (maps != null) {
for (Map map : maps) {
String wareId = (String) map.get("wareId");
List<String> skuIds = (List<String>) map.get("skuIds");
OrderInfo subOrderInfo = new OrderInfo();
// 属性拷贝
BeanUtils.copyProperties(orderInfoOrigin, subOrderInfo);
// 防止主键冲突
subOrderInfo.setId(null);
//设置付订单id
subOrderInfo.setParentOrderId(orderId);
// 赋值仓库Id
subOrderInfo.setWareId(wareId);
// 计算子订单的金额: 必须有订单明细
// 获取到子订单明细
// 声明一个集合来存储子订单明细
ArrayList<OrderDetail> orderDetails = new ArrayList<>();
//获取父订单商品总明细
List<OrderDetail> orderDetailList = orderInfoOrigin.getOrderDetailList();
// 表示主主订单明细中获取到子订单的明细
if (orderDetailList != null && orderDetailList.size() > 0) {
for (OrderDetail orderDetail : orderDetailList) {
// 获取子订单明细的商品Id
for (String skuId : skuIds) {
//对比是否是当前仓库的商品,就收集
if (Long.parseLong(skuId) == orderDetail.getSkuId().longValue()) {
// 将订单明细添加到集合
orderDetails.add(orderDetail);
}
}
}
}
subOrderInfo.setOrderDetailList(orderDetails);
// 计算总金额
subOrderInfo.sumTotalAmount();
// 保存子订单 submitOrdser(subOrderInfo)
saveOrderInfo(subOrderInfo);
// 将子订单添加到集合中!
orderInfoArrayList.add(subOrderInfo);
}
}
// 修改原始订单的状态
updateOrderStatus(orderId, ProcessStatus.SPLIT);
return orderInfoArrayList;
}
拆单接口控制器:OrderApiController:
/**
* 拆单业务
* @param request
* @return
*/
@RequestMapping("orderSplit")
public String orderSplit(HttpServletRequest request){
String orderId = request.getParameter("orderId");
String wareSkuMap = request.getParameter("wareSkuMap");
// 拆单:获取到的子订单集合
List<OrderInfo> subOrderInfoList = orderService.orderSplit(Long.parseLong(orderId),wareSkuMap);
// 声明一个存储map的集合
ArrayList<Map> mapArrayList = new ArrayList<>();
// 生成子订单集合
for (OrderInfo orderInfo : subOrderInfoList) {
Map map = orderService.initWareOrder(orderInfo);
// 添加到集合中!
mapArrayList.add(map);
}
return JSON.toJSONString(mapArrayList);
}
前面已经写了:
实现类
多了两条子订单
库存系统表:
订单任务
订单任务详情
(2)取消订单业务补充关闭支付记录
用户没有点击扫码支付,不会调用支付宝的接口,这个时候订单超时后直接关闭订单就行了,当点击扫码支付后,会调用支付宝接口这个时候就会生成PaymentInfo对象,这个时候超时了,还需要关闭支付记录
此时如果用户扫码了,但是没有支付,订单超时了,这个时候还需要关闭支付宝交易记录
关闭订单流程图:
在处理超时订单里:添加代码
在MqConst中添加常量
/**
* 关闭交易
*/
public static final String EXCHANGE_DIRECT_PAYMENT_CLOSE = "exchange.direct.payment.close";
public static final String ROUTING_PAYMENT_CLOSE = "payment.close";
//队列
public static final String QUEUE_PAYMENT_CLOSE = "queue.payment.close";
根据业务进行发送1或2,2是有支付记录
在取消订单实现类中发送消息关闭交易
更改接口
2是有支付记录,才发送消息
@Override
public void execExpiredOrder(Long orderId) {
// orderInfo
updateOrderStatus(orderId, ProcessStatus.CLOSED);
rabbitService.sendMessage(MqConst.EXCHANGE_DIRECT_PAYMENT_CLOSE, MqConst.ROUTING_PAYMENT_CLOSE, orderId);
}
service-payment模块接收消息
编写消费者
package com.atguigu.gmall.payment.receiver;
@Component
public class PaymentReceiver {
@Autowired
private PaymentService paymentService;
@SneakyThrows
@RabbitListener(bindings = @QueueBinding(
value = @Queue(value = MqConst.QUEUE_PAYMENT_CLOSE,durable = "true"),
exchange = @Exchange(value = MqConst.EXCHANGE_DIRECT_PAYMENT_CLOSE),
key = {MqConst.ROUTING_PAYMENT_CLOSE}
))
public void closePayment(Long orderId , Message message, Channel channel){
if (null != orderId){
// 关闭交易
paymentService.closePayment(orderId);
}
// 手动ack
channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
}
}
编写关闭交易记录接口与实现类
PaymentService
/**
* 关闭过期交易记录
* @param orderId
*/
void closePayment(Long orderId);
@Override
public void closePayment(Long orderId) {
// 设置关闭交易记录的条件 118
QueryWrapper<PaymentInfo> paymentInfoQueryWrapper = new QueryWrapper<>();
paymentInfoQueryWrapper.eq("order_id",orderId);
// 如果当前的交易记录不存在,则不更新交易记录
Integer count = paymentInfoMapper.selectCount(paymentInfoQueryWrapper);
if (null == count || count.intValue()==0) return;
// 在关闭支付宝交易之前。还需要关闭paymentInfo
PaymentInfo paymentInfo = new PaymentInfo();
paymentInfo.setPaymentStatus(PaymentStatus.ClOSED.name());
paymentInfoMapper.update(paymentInfo,paymentInfoQueryWrapper);
}
提交订单超时后会关闭订单
(3)支付宝关闭交易
AlipayService接口
/***
* 关闭交易
* @param orderId
* @return
*/
Boolean closePay(Long orderId);
编写实现类
@SneakyThrows
@Override
public Boolean closePay(Long orderId) {
OrderInfo orderInfo = orderFeignClient.getOrderInfo(orderId);
AlipayTradeCloseRequest request = new AlipayTradeCloseRequest();
HashMap<String, Object> map = new HashMap<>();
// map.put("trade_no",paymentInfo.getTradeNo()); // 从paymentInfo 中获取!
map.put("out_trade_no",orderInfo.getOutTradeNo());
map.put("operator_id","YX01");
request.setBizContent(JSON.toJSONString(map));
AlipayTradeCloseResponse response = alipayClient.execute(request);
if(response.isSuccess()){
System.out.println("调用成功");
return true;
} else {
System.out.println("调用失败");
return false;
}
}
编写控制器AlipayController :
http://localhost:8205/api/payment/alipay/closePay/25
// 根据订单Id关闭订单
@GetMapping("closePay/{orderId}")
@ResponseBody
public Boolean closePay(@PathVariable Long orderId){
Boolean aBoolean = alipayService.closePay(orderId);
return aBoolean;
}
(4)查询支付交易记录
编写接口:AlipayService
/**
* 根据订单查询是否支付成功!
* @param orderId
* @return
*/
Boolean checkPayment(Long orderId);
编写实现类
@SneakyThrows
@Override
public Boolean checkPayment(Long orderId) {
// 根据订单Id 查询订单信息
OrderInfo orderInfo = orderFeignClient.getOrderInfo(orderId);
AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
HashMap<String, Object> map = new HashMap<>();
map.put("out_trade_no",orderInfo.getOutTradeNo());
// 根据out_trade_no 查询交易记录
request.setBizContent(JSON.toJSONString(map));
AlipayTradeQueryResponse response = alipayClient.execute(request);
if(response.isSuccess()){
System.out.println("调用成功");
return true;
} else {
System.out.println("调用失败")
return false;
}
}
编写控制器
// 查看是否有交易记录
@RequestMapping("checkPayment/{orderId}")
@ResponseBody
public Boolean checkPayment(@PathVariable Long orderId){
// 调用退款接口
boolean flag = alipayService.checkPayment(orderId);
return flag;
}
没有支付返回false
支付后返回true
在AlipayController 添加查询PaymentInfo 数据接口
查询支付记录
@GetMapping("getPaymentInfo/{outTradeNo}")
@ResponseBody
public PaymentInfo getPaymentInfo(@PathVariable String outTradeNo){
PaymentInfo paymentInfo = paymentService.getPaymentInfo(outTradeNo, PaymentType.ALIPAY.name());
if (null!=paymentInfo){
return paymentInfo;
}
return null;
}
(5)PaymentFeignClient 远程接口
创建service-payment-client
package com.atguigu.gmall.payment.client;
@FeignClient(value = "service-payment",fallback = PaymentDegradeFeignClient.class)
public interface PaymentFeignClient {
@GetMapping("api/payment/alipay/closePay/{orderId}")
Boolean closePay(@PathVariable Long orderId);
@GetMapping("api/payment/alipay/checkPayment/{orderId}")
Boolean checkPayment(@PathVariable Long orderId);
@GetMapping("api/payment/alipay/getPaymentInfo/{outTradeNo}")
PaymentInfo getPaymentInfo(@PathVariable String outTradeNo);
}
PaymentDegradeFeignClient实现类
@Component
public class PaymentDegradeFeignClient implements PaymentFeignClient {
@Override<dependency>
<groupId>com.atguigu.gmall</groupId>
<artifactId>service-payment-client</artifactId>
<version>1.0</version>
</dependency>
public Boolean closePay(Long orderId) {
return null;
}
@Override
public Boolean checkPayment(Long orderId) {
return null;
}
@Override
public PaymentInfo getPaymentInfo(String outTradeNo) {
return null;
}
}
(6)整合关闭过期订单
在订单service-order项目中添加依赖
<dependency>
<groupId>com.atguigu.gmall</groupId>
<artifactId>service-payment-client</artifactId>
<version>1.0</version>
</dependency>
OrderReceiver 整合代码
接口:OrderService
/**
* 更新过期订单
* @param orderId
* @param flag
*/
void execExpiredOrder(Long orderId,String flag);
@Override
public void execExpiredOrder(Long orderId,String flag) {
// 调用方法 状态
updateOrderStatus(orderId,ProcessStatus.CLOSED);
//2代表支付宝有交易记录就是扫码了没有支付
if ("2".equals(flag)){
// 发送消息队列,关闭支付宝的交易记录。
rabbitService.sendMessage(MqConst.EXCHANGE_DIRECT_PAYMENT_CLOSE,MqConst.ROUTING_PAYMENT_CLOSE,orderId);
}
}
@Autowired
private RabbitService rabbitService;
@Autowired
private PaymentFeignClient paymentFeignClient;
// 监听消息
@SneakyThrows
@RabbitListener(queues = MqConst.QUEUE_ORDER_CANCEL)
public void orderCancel(Long orderId, Message message, Channel channel){
try {
// 判断订单id 是否存在!
if (orderId!=null){
// 根据订单Id 查询订单对象
OrderInfo orderInfo = orderService.getById(orderId);
// 判断
if(orderInfo!=null && "UNPAID".equals(orderInfo.getOrderStatus()) && "UNPAID".equals(orderInfo.getProcessStatus())){
// 关闭过期订单! 还需要关闭对应的 paymentInfo ,还有alipay.
// orderService.execExpiredOrder(orderId);
// 查询支付记录信息paymentInfo -远程调用是否存在!
PaymentInfo paymentInfo = paymentFeignClient.getPaymentInfo(orderInfo.getOutTradeNo());
// 判断 用户点击了扫码支付
if(paymentInfo!=null && "UNPAID".equals(paymentInfo.getPaymentStatus())){
// 查看是否有支付宝交易记录!
Boolean flag = paymentFeignClient.checkPayment(orderId);
// 判断
if (flag){
// flag = true , 有支付宝记录
// 调用关闭接口! 扫码未支付这样才能关闭成功!
Boolean result = paymentFeignClient.closePay(orderId);
// 判断
if (result){
// result = true; 关闭成功!未付款!需要关闭orderInfo, paymentInfo,Alipay
orderService.execExpiredOrder(orderId,"2");
}else {
// result = false; 表示付款!
// 说明已经付款了! 正常付款成功都会走异步通知!
}
}else {
// 没有交易记录,不需要关闭支付! 需要关闭orderInfo, paymentInfo
//关闭订单,关闭支付记录
orderService.execExpiredOrder(orderId,"2");
}
}else {
// 只关闭订单orderInfo!
orderService.execExpiredOrder(orderId,"1");
}
}
}
} catch (Exception e) {
// 写入日志...
e.printStackTrace();
}
// 手动确认
channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
}
不进行支付