laravel电商学习系列-06 支付模块

1. 前言

支付模块不管在哪个系统都是重要的(跟钱有关系的能不重要嘛)。课程中使用的是yansongda/pay的支付库,集成了支付宝、微信支付,使用方便。支付模块主要是按照支付通道的支付规则编码实现,其实质就是接口请求。课程中侧重开发实现,介绍了支付拓展包的使用。因此,支付集成的部分,本章节暂且跳过,只记录学习点。
课程传送门-支付集成

此外,课程中还实现了电商行业大热分期付款。本章节主要梳理课程中对分期付款的实现方案。
课程传送门-分期付款

2. 功能分析

2.1 支付集成

2.1.1 编码学习

支付模块单拎出来就很抗打,涉及到加解密、字符编码的处理,代码封装。

  • 实现过程
    支付模块比较有意思的是代码实现部分,不同支付通道支持的支付方式不同,传递的参数、验证方式不同。怎么样把不同支付通道的代码封装起来,方便统一处理调用值得去研究。
  • 容器的使用

2.2 分期付款

分期付款可以看作是新的一种支付网关,对于一个订单来说,它跟银行卡支付、支付宝支付一样,都可以作为支付方式,只是它每一期分期付款还是依赖于真实的支付方式支付。


laravel电商学习系列-06 支付模块_第1张图片
分期付款的逻辑分析

2.2.1 需求分析

分期付款的业务逻辑如下:

  • 只有当商品订单总金额高于某个数值时才可以使用分期付款;
  • 用户使用分期付款时,需要选择还款期限,通常为 3 个月的倍数;
  • 使用分期付款需要支付手续费,不同的还款期限手续费费率不同,还款期限越久费率越高;
  • 分期付款的手续费与银行贷款的利息不同,银行贷款的利息会随着还款而逐渐降低,而分期付款的手续费则是固定的;
  • 使用分期付款后,用户需要立即支付第一期的费用,当第一期费用支付成功后,对应的商品订单状态即变为已支付;
  • 用户需每 30 天还款一次,如果在还款截止日期之后仍未还款,需支付逾期费,逾期费按天计算;
  • 逾期之后产生的逾期费用最多不超过当期的本金 + 手续费;
  • 每一期还款金额计算公式:(本金 + 手续费) / 还款期数 + 当期逾期费;
  • 使用了分期付款的商品订单如果发生退款,则退回所有已支付的本金,手续费与逾期费不退回。

2.2.2 实现逻辑

  1. 选择分期付款下单:
  • 在用户选择分期付款时,按照分期期数和金额计算出每一期需要还款的本金、手续费、还款时间等还款信息;
  • 再用一个定时脚本去计算当期的逾期费;
  1. 分期还款支付:(请求支付和支付回调与普通商品的不一样,需要单独实现)
  • 请求支付,使用当期的流水号、当期支付金额、分期的回调地址和返回地址去请求第三方支付;
  • 按照分期逻辑实现支付回调,更新当期支付信息,若是第一期需更新订单的状态和支付信息,以及分期状态;
  1. 分期退款:
    分期的每一期批量退款,修改订单退款状态;


    laravel电商学习系列-06 支付模块_第2张图片
    分期付款流程图

2.2.3 表设计

分期分款可以选择还款期数,需要计算每一期还款的本金、手续费、还款时间,以及需要保存每一期还款的具体支付方式和支付单号。因此,我们需要用两张表来分别保存分期信息和每期分期的详细信息。
具体表结构如下:

# 分期表
CREATE TABLE `installments` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT, # 自增ID
  `no` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, # 分期单号
  `user_id` int(10) unsigned NOT NULL, # 所属用户ID
  `order_id` int(10) unsigned NOT NULL, # 对应订单ID
  `total_amount` decimal(8,2) NOT NULL, # 总本金
  `count` int(10) unsigned NOT NULL, # 还款期数
  `fee_rate` double(8,2) NOT NULL, # 手续费率
  `fine_rate` double(8,2) NOT NULL, # 逾期费率
  `status` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'pending', # 还款状态,默认未执行
  `created_at` timestamp NULL DEFAULT NULL, # 创建时间
  `updated_at` timestamp NULL DEFAULT NULL, # 更新时间
  PRIMARY KEY (`id`),
  UNIQUE KEY `installments_no_unique` (`no`),
  KEY `installments_user_id_foreign` (`user_id`),
  KEY `installments_order_id_foreign` (`order_id`),
  CONSTRAINT `installments_order_id_foreign` FOREIGN KEY (`order_id`) REFERENCES `orders` (`id`) ON DELETE CASCADE,
  CONSTRAINT `installments_user_id_foreign` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

# 分期项表
CREATE TABLE `installment_items` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT, # 自增ID
  `installment_id` int(10) unsigned NOT NULL, # 分期ID
  `sequence` int(10) unsigned NOT NULL, # 期数
  `base` decimal(8,2) NOT NULL, # 当期本金
  `fee` decimal(8,2) NOT NULL, # 当期手续费
  `fine` decimal(8,2) DEFAULT NULL, # 当期逾期费
  `due_date` datetime NOT NULL, # 还款截止日期
  `paid_at` datetime DEFAULT NULL, # 还款日期
  `payment_method` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL, # 还款支付方式
  `payment_no` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL, # 换的支付单号
  `refund_status` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'pending', # 退款状态 默认未退款
  `created_at` timestamp NULL DEFAULT NULL, # 创建时间
  `updated_at` timestamp NULL DEFAULT NULL, # 更新时间
  PRIMARY KEY (`id`),
  KEY `installment_items_installment_id_foreign` (`installment_id`),
  CONSTRAINT `installment_items_installment_id_foreign` FOREIGN KEY (`installment_id`) REFERENCES `installments` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

2.3.4 代码借鉴

本章节业务逻辑有点复杂,实现方案不算复杂,学习到了以下几点:

  • 浮点数的计算方式(使用 bcmath)
  • 在处理大数据量的数据库操作时,使用chunkById减少内存占用;

上一节:05 购物车&订单模块
下一节:07 优惠券模块

你可能感兴趣的:(laravel电商学习系列-06 支付模块)