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

目录:

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

不进行支付 

 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

CrossOver24.0.5破解版免费下载和永久激活图文教程,苹果电脑怎么玩《黑神话:悟空》

CrossOver24可以玩《黑神话&#xff1a;悟空》么&#xff1f;答案是可以的。 1、首先我们需要下载CrossOver24软件。 CrossOver24安装包夸克网盘链接&#xff1a;https://pan.quark.cn/s/35e64d746778 2、下载完成后&#xff0c;我们双击CrossOver.pkg开始安装&#xff0c;然…

Uniapp + Vue3 + Vite +Uview + Pinia 实现购物车功能(最新附源码保姆级)

Uniapp Vue3 Vite Uview Pinia 实现购物车功能&#xff08;最新附源码保姆级&#xff09; 1、效果展示2、安装 Pinia 和 Uview3、配置 Pinia4、页面展示 1、效果展示 2、安装 Pinia 和 Uview 官网 https://pinia.vuejs.org/zh/getting-started.html安装命令 cnpm install pi…

搭建Windows下的Rust开发环境

【图书介绍】《Rust编程与项目实战》-CSDN博客 《Rust编程与项目实战》(朱文伟&#xff0c;李建英)【摘要 书评 试读】- 京东图书 (jd.com) Rust编程与项目实战_夏天又到了的博客-CSDN博客 2.1.1 安装vs_buildtools 在Windows系列操作系统中&#xff0c;Rust开发环境需要依…

机器学习课程学习周报十二

机器学习课程学习周报十二 文章目录 机器学习课程学习周报十二摘要Abstract一、机器学习部分1.1 fGAN: General Framework of GAN1.2 CycleGAN1.3 Auto-Encoder1.4 概率论复习&#xff08;一&#xff09; 总结 摘要 本周的学习内容涵盖了fGAN框架、CycleGAN、自编码器以及概率…

Linux | 探索 Linux 信号机制:信号的产生和自定义捕捉

信号是 Linux 操作系统中非常重要的进程控制机制&#xff0c;用来异步通知进程发生某种事件。理解信号的产生、阻塞、递达、捕捉等概念&#xff0c;可以帮助开发者更好地编写健壮的应用程序&#xff0c;避免由于未处理的信号导致程序异常退出。本文将带你从基础概念开始&#x…

数据结构基础详解:哈希表【C语言代码实践篇】开放地址法__拉链法_哈希表的创建_增删查操作详解

文章目录 1.哈希表代码实现之开放地址法1.1 开放地址法创建哈希表1.2 开放地址法之查找1.3 开放地址法之插入1.4 开放地址法之删除 2.哈希表代码实现之链地址法(拉链法)2.1 链地址法之创建哈希表2.2 链地址法之查找2.3 链地址法之插入2.4 链地址法之删除 1.哈希表代码实现之开放…

Mac电脑剪切板在哪里找 苹果电脑剪切板打开教程【详解】

Windows 和 Mac 电脑在使用方式上存在一些差异&#xff0c;许多习惯了 Windows 系统的用户初次接触 Mac 时可能会对某些操作感到困惑。比如&#xff0c;很多人会问&#xff1a;Mac 上的剪贴板在哪里&#xff1f;如果你也有这样的疑问&#xff0c;不妨看看下面这篇关于如何在 Ma…

MySQL查询执行(四):查一行也很慢

假设存在表t&#xff0c;这个表有两个字段id和c&#xff0c;并且我在里面插入了10万行记录。 -- 创建表t CREATE TABLE t (id int(11) NOT NULL,c int(11) DEFAULT NULL,PRIMARY KEY (id) ) ENGINEInnoDB;-- 通过存储过程向t写入10w行数据 delimiter ;; create procedure idat…

Android Studio新建工程(Java语言环境)

一、新建工程流程(java语言环境) 1、File->New->New Project 2、选择“Empty Views Activity” -> Next 3、创建项目名称/项目路径/语言环境 1&#xff09;项目名称&#xff1a;使用默认Name 或 修改Name 2) Package name&#xff1a;每个项目的这个名称唯一&…

饿了么基于Flink+Paimon+StarRocks的实时湖仓探索

摘要&#xff1a;本文整理自饿了么大数据架构师、Apache Flink Contributor 王沛斌老师在8月3日 Streaming Lakehouse Meetup Online&#xff08;Paimon x StarRocks&#xff0c;共话实时湖仓架构&#xff09;上的分享。主要分为以下三个内容&#xff1a; 饿了么实时数仓演进之…

self-play RL学习笔记

让AI用随机的路径尝试新的任务&#xff0c;如果效果超预期&#xff0c;那就更新神经网络的权重&#xff0c;使得AI记住多使用这个成功的事件&#xff0c;再开始下一次的尝试。——llya Sutskever 这两天炸裂朋友圈的OpenAI草莓大模型o1和此前代码能力大幅升级的Claude 3.5&…

手机玩机常识____展讯芯片刷机平台ResearchDownload的一些基本常识与问题解决

展讯ResearchDownload工具 展讯芯片的刷机工具--ResearchDownload下载工具"是一款专为用户设计的高效、便捷的下载管理软件&#xff0c;它能够帮助用户快速、稳定地从互联网上获取各种文件。这款工具以其强大的功能和良好的用户体验&#xff0c;在众多展讯芯片下载工具中脱…

Python [ GUI编程自学 ],虽然但是,还是想出一个系列

Python [ GUI编程自学 ]&#xff0c;虽然但是&#xff0c;还是想出一个系列。 目前跟着哔站自学完毕&#xff0c;皮毛了解了&#xff0c;本文GUI一系列文章请查看Python_GUI编程专栏&#xff01; 本篇主要介绍了事件处理机制&#xff1a;事件处理原理&#xff08;感觉和之前学的…

解决win11 使用wsl工具,不能使用systemctl

使用systemctl命令出现报错&#xff1a; System has not been booted with systemd as init system (PID 1). Can‘t operate. 默认情况下并不启用 systemd&#xff0c;而是使用了其他轻量级的初始化系统&#xff08;SysV init初始化系统&#xff09;。这导致一些需要 system…

利用未标记数据的半监督学习在模型训练中的效果评估

数据科学家在实践中经常面临的一个关键挑战是缺乏足够的标记数据来训练可靠且准确的模型。标记数据对于监督学习任务&#xff08;如分类或回归&#xff09;至关重要。但是在许多领域&#xff0c;获取标记数据往往成本高昂、耗时或不切实际。相比之下&#xff0c;未标记数据通常…

Java获取随机数

在Java中获取随机数通常会使用java.util.Random类或者Math.random()方法 1.java.util.Random java.util.Random类用于生成伪随机数。 // 使用无参构造方法创建Random对象Random rand new Random();// 生成一个[0, 100)范围内的随机整数int randomInt rand.nextInt(100);Sys…

linux使用命令行编译qt.cpp

步骤&#xff1a; mkdir qttestcd qttestvim hello.cpp #include <QApplication> #include <QDialog> #include <QLabel> int main(int argc,char* argv[]) {QApplication a(argc,argv);QLabel label("aaa");label.resize(100,100);label.show()…

vulnhub(6):Tr0ll(隐藏目录、hydra密码爆破、内核漏洞提权)

端口 nmap主机发现 nmap -sn 192.168.178.0/24 ​ Nmap scan report for 192.168.178.33 Host is up (0.00020s latency). ​ 33是新出现的机器&#xff0c;他就是靶机 nmap端口扫描 nmap -Pn 192.168.178.33 -p- --min-rate 10000 -oA nmap/scan 扫描开放端口保存到 nmap/sca…

【FATFS】FATFS简介及下载

1、FATFS简介 FatFs 是一个针对嵌入式系统开发的通用文件系统模块&#xff0c;主要用于支持 FAT 文件系统。它最初由 ChaN 开发&#xff0c;并被广泛应用于嵌入式设备上。FatFs 以其轻量级、可配置和设备无关的特性著称&#xff0c;支持 FAT12、FAT16、FAT32 以及 exFAT 文件系…

【iOS】单例模式

目录 前言单例模式认识单例模式单例模式的特点及使用情景单例模式的使用单例模式的实现步骤&#xff1a;完整代码 总结 前言 在进行大项目编写之前&#xff0c;开始对前面比较重要的知识进行回顾和重新学习&#xff0c;单例模式在软件开发设计中是比较重要的&#xff0c;尤其是…