尚品汇-订单拆单、支付宝关闭交易、关闭过期订单整合(五十)

news2024/12/23 17:24:59

目录:

(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);
}

不进行支付 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2135735.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

玩转扩展库,温湿度传感器篇!—合宙Air201资产定位模组LuatOS快速入门05

随着LuatOS快速入门系列教程的推出&#xff0c;小伙伴们学习热情高涨。 合宙Air201不仅支持三种定位方式&#xff0c;还具有丰富的扩展功能&#xff0c;通过外扩BTB链接方案&#xff0c;最多可支持21个IO接口&#xff1a;SPI、I2C、UART等多种接口全部支持。 本期&#xff0c…

electron-vite vue3离线使用monaco-editor

目录 1.搭建一个 electron-vite 项目 2.安装monaco-editor和vite-plugin-monaco-editor 3.electron.vite.config.mjs配置 4.创建 worker.js并在main.js 引入 5.创建组件 MonacoVite.vue 组件 6. App.vue中引入组件 7.运行测试 1.搭建一个 electron-vite 项目 pnpm creat…

如何在算家云搭建TripoSR(三维重建)

一、模型介绍 TripoSR是由Tripo AI和Stability AI合作开发的先进开源模型&#xff0c;能在短时间内从单张图片生成高质量 3D 模型。 利用大型重建模型&#xff08;LRM&#xff09;的原理&#xff0c;TripoSR带来了关键的进步&#xff0c;大大提高了3D重建的速度和质量。模型的…

秒验HarmonyOS NEXT集成指南

开发工具&#xff1a;DevEco Studio 集成方式&#xff1a;在线集成 HarmonyOS API支持&#xff1a;> 12 集成前准备 注册账号 使用MobSDK之前&#xff0c;需要先在MobTech官网注册开发者账号&#xff0c;并获取MobTech提供的AppKey和AppSecret&#xff0c;详情可以点击查看…

基于SpringBoot+Vue的校内跑腿业务管理系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、SSM项目源码 系统展示 【2025最新】基于JavaSpringBootVueMySQL的…

使用 QEMU 模拟器运行 FreeRTOS 实时操作系统

文章目录 QEMU 官网QEMU 文档QEMU 简介QEMU 安装QEMU 命令启动虚拟机串口控制台监控命令行 FreeRTOS安装编译工具FreeRTOS 源码RISC-V-Qemu-virt_GCC 示例编译 RISC-V-Qemu-virt_GCC启动虚拟机运行 FreeRTOS QEMU 官网 https://www.qemu.org/ QEMU 文档 https://www.qemu.or…

爆品只是日百商家的表面“风光”

前不久&#xff0c;#大学生买爆台州商家的移动收纳筐#的话题上了热搜。现在的大学生相比以前讲究多了&#xff0c;虽然生活费没涨多少&#xff0c;但生活一定要精致。比如&#xff0c;在有限的预算内买各种收纳神器&#xff0c;把宿舍整理地井井有条。 爆品&#xff0c;往往成…

2024.9.14(RC和RS)

一、replicationcontroller &#xff08;RC&#xff09; 1、更改镜像站 [rootk8s-master ~]# vim /etc/docker/daemon.json {"registry-mirrors": ["https://do.nark.eu.org","https://dc.j8.work","https://docker.m.daocloud.io",&…

windows远程桌面连接ubuntu

通过 Windows 远程连接到 Ubuntu 的桌面环境&#xff0c;可以使用 远程桌面协议&#xff08;RDP&#xff09; 来实现远程登录。 准备工作 一台安装了 Ubuntu 的服务器或计算机。一台 Windows 电脑&#xff08;安装远程桌面客户端&#xff09;。两台机器必须在同一网络中&…

M3U8是什么,如何解析下载

M3U8是什么&#xff1f;如何解析下载 M3U8是苹果公司推出的视频播放标准&#xff0c;准确来说是一种索引文件&#xff0c;使用M3U8文件实际上是通过它来解析对应的放在服务器上的视频网络地址&#xff0c;从而实现在线播放。M3U8文件使用UTF-8字符编码。M3U8是一种常见的流媒体…

基于SpringBoot的甜品店管理系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、SSM项目源码 系统展示 【2025最新】基于JavaSpringBootVueMySQL的蛋糕甜品店管理系…

下载docker镜像报错,dial tcp x.x.x.x:443: connect: connection refused

原因是:国外的连接超时了. 解决方案改为阿里云的数据源 打开阿里云 搜索&#xff1a;容器镜像服务 ACR 把你自己的这个直接复制在linux sudo mkdir -p /etc/docker sudo tee /etc/docker/daemon.json <<-EOF { "registry-mirrors": ["你自己的"] }…

接口发送 xml 格式的数据如何测试?

什么是 xml &#xff1f; xml 是一种和 html 非常类似的语言&#xff0c;采取一定的格式展示数据。比如&#xff1a; 这个例子非常形象的指明&#xff1a; 这是一个便条 便条是给你的 便条是我写的 标题是&#xff1a;提醒 内容是&#xff1a;今晚八点&#xff0c;不见不散…

【docker】docker 关键技术 —— 镜像制作

docker 镜像制作 镜像制作及原因Docker 镜像制作方式快照方式制作镜像制作命令 Dockerfile 制作镜像Dockerfile 是什么Dockerfile 格式为什么需要 Dockerfilegitee 详细使用 Dockerfile 教程 镜像制作及原因 镜像制作是因为某种需求&#xff0c;官方的镜像无法满足需求&#x…

云服务器和物理服务器的区别在哪

在当今数字化的时代&#xff0c;服务器在企业和个人的信息技术架构中扮演着至关重要的角色。其中&#xff0c;云服务器和物理服务器是两种主要的服务器类型&#xff0c;它们在多个方面存在着明显的区别。 一、硬件方面 物理服务器是实实在在的物理硬件设备&#xff0c;它由机…

写论文还在卡壳?教你用ChatGPT轻松搞定过渡段落!

AIPaperGPT&#xff0c;论文写作神器~ https://www.aipapergpt.com/ 在写论文的路上&#xff0c;最让人头疼的除了查重率飙升&#xff0c;估计就是文献综述了吧&#xff01; 想想看&#xff0c;文献一篇接着一篇&#xff0c;脑子都快炸了&#xff0c;还得想办法把它们连接得…

使用JLink V8烧写友善之臂Mini2440 Superboot2440.bin到NORflash里

1 开发环境 PC&#xff1a;Windows 11、开发板Mini2440、仿真器JLink V8、Jlink转接板、JLinkARM烧录工具V4.34版本Setup_JLinkARM_V434.exe 准备工作&#xff1a;安装好烧录工具JLinkARM&#xff0c;按照网上的接线方法将PC、开发板和JLink仿真器连接起来。 组网&#xff1a;…

Radware Alteon 负载均衡-基于URL Filetype的七层负载均衡

作者&#xff1a;Xiaolei Ren Radware Alteon作为一款高性能的负载均衡器&#xff0c;其基于URL Filetype的七层负载均衡功能为众多企业提供了灵活、高效的解决方案。 该案例实现如下需求&#xff1a;当客户端访问服务器时&#xff0c;默认访问10.200.1.100&#xff0c;在ht…

使用Let’s Encrypt 配置 SSL 证书去除浏览器不安全告警

Let’s Encrypt是什么 https://letsencrypt.org/zh-cn/about/如何操作进行配置实现ssl认证 使用 certbot 获取 Let’s Encrypt 的免费 SSL 证书 更新系统软件包 sudo yum update -y安装 EPEL 仓库(Certbot 通常位于 EPEL 仓库中): sudo yum

【C++】STL——vecot的模拟实现

目录 前言总体结构默认成员函数构造函数拷贝构造赋值重载析构函数 vector的相关容量空间以及访问的实现capacity()和size()迭代器实现operator[]reserve vector类对象的修改操作尾插尾删任意位置插入任意位置删除交换和清理 前言 前面我们已经学习了解了vector重要接口的使用&a…