点击上方“芋道源码”,选择“置顶公众号”
技术文章第一时间送达!
源码精品专栏
精尽 Dubbo 原理与源码 69 篇
精尽 Netty 原理与源码 61 篇
来源:http://t.cn/EAJS7Sk
1. 前言2. 付款2.1 成功2.2 人祸2.4 天灾2.4 注释2.5 表结构2.5.1 交易表2.5.2 支付记录表2.5.3 订单表3. 运输4. 收货5. 退换货5.1 售后申请表5.2 售后表6. 评价6.1 评价数据表7. 致谢
1. 前言
用户交易将经历一段艰辛的历程,一般用户感觉不到,实际程序是经历了一段生死离别。具体付款流程如下
不(wo)是(gu)这(yi)张(chuan)图(de),请看正经流程图
之前的几篇文章介绍了
购物车如何设计
用户系统如何设计
商品系统如何设计
其实他们都在为交易系统做铺垫,一个产品如果没有收入,那这只能是寺庙的公益产品。任何产品最终都要走向这步 (收钱)。
2. 付款
用户付款过程中有很多场景也会出现意外,以下是我碰到的“天灾人祸”
2.1 成功
用户发起微信支付并成功支付
用户发起支付宝支付并成功支付
用户发起银联支付并成功支付
用户发起其他支付并成功支付
2.2 人祸
用户发起微信支付但取消支付
用户发起支付宝支付但取消支付
用户发起银联支付但取消支付
用户发起其他支付但取消支付
2.4 天灾
用户发起微信支付“手机爆炸了”
用户发起支付宝支付“瞬间没网了”
用户发起银联支付“老婆来电话了”
用户发起其他支付“老板进来了”
2.4 注释
遇到以上的情况,不要害怕、不要惊慌,并且不要“理会”,你只需要将这些操作记录下来即可。 正常我们都会将用户通过哪种支付方式存储到订单表中,方便查询。我想说这种做法没错,但是少了点什么,你应该有一张交易记录表,来记录用户发起了多少次支付,只有支付成功的时候方可记录到订单表中。这样做的优点有以下两点
订单表是比较重要的,迫不得已尽量不要操作这张表,防止出现意外,订单表除了收货发货外一般没有其他需要操作的地方。
可以记录每次用户发起支付的时间,通过所谓大数据分析用户对产品的需求度和认可度,如果用户多次发起付款但取消支付,那就说明(他没钱)他可能很期望得到,但是因为某种原因一直在犹豫,这个时候可以针对当前用户做优惠处理,例如发一张优惠券等等。
2.5 表结构
2.5.1 交易表
CREATE TABLE `transaction` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`order_sn` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '交易单号',
`member_id` bigint(20) NOT NULL COMMENT '交易的用户ID',
`amount` decimal(8,2) NOT NULL COMMENT '交易金额',
`integral` int(11) NOT NULL DEFAULT '0' COMMENT '使用的积分',
`pay_state` tinyint(4) NOT NULL COMMENT '支付类型 0:余额 1:微信 2:支付宝 3:xxx',
`source` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '支付来源 wx app web wap',
`status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '支付状态 -1:取消 0 未完成 1已完成 -2:异常',
`completion_time` int(11) NOT NULL COMMENT '交易完成时间',
`note` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '备注',
`created_at` timestamp NULL DEFAULT NULL,
`updated_at` timestamp NULL DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `transaction_order_sn_member_id_pay_state_source_status_index` (`order_sn`(191),`member_id`,`pay_state`,`source`(191),`status`)
) ENGINE=InnoDB AUTO_INCREMENT=36 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
2.5.2 支付记录表
CREATE TABLE `transaction_record` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`order_sn` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
`events` text COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '事件详情',
`result` text COLLATE utf8mb4_unicode_ci COMMENT '结果详情',
`created_at` timestamp NULL DEFAULT NULL,
`updated_at` timestamp NULL DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=36 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
这个记录表可能让你匪夷所思,不知你对日志有什么概念,但我能说的就是,将用户的所有动作全部记录下来。这是很重要的,早晚你会懂。
2.5.3 订单表
CREATE TABLE `order` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`order_no` varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '订单编号',
`order_sn` varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '交易号',
`member_id` int(11) NOT NULL COMMENT '客户编号',
`supplier_id` int(11) NOT NULL COMMENT '商户编码',
`supplier_name` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '商户名称',
`order_status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '订单状态 0未付款,1已付款,2已发货,3已签收,-1退货申请,-2退货中,-3已退货,-4取消交易',
`after_status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '用户售后状态 0 未发起售后 1 申请售后 -1 售后已取消 2 处理中 200 处理完毕',
`product_count` int(11) NOT NULL DEFAULT '0' COMMENT '商品数量',
`product_amount_total` decimal(12,4) NOT NULL COMMENT '商品总价',
`order_amount_total` decimal(12,4) NOT NULL DEFAULT '0.0000' COMMENT '实际付款金额',
`logistics_fee` decimal(12,4) NOT NULL COMMENT '运费金额',
`address_id` int(11) NOT NULL COMMENT '收货地址编码',
`pay_channel` tinyint(4) NOT NULL DEFAULT '0' COMMENT '支付渠道 0余额 1微信 2支付宝',
`out_trade_no` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '订单支付单号',
`escrow_trade_no` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '第三方支付流水号',
`pay_time` int(11) NOT NULL DEFAULT '0' COMMENT '付款时间',
`delivery_time` int(11) NOT NULL DEFAULT '0' COMMENT '发货时间',
`order_settlement_status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '订单结算状态 0未结算 1已结算',
`order_settlement_time` int(11) NOT NULL DEFAULT '0' COMMENT '订单结算时间',
`is_package` enum('0','1') COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '0' COMMENT '是否是套餐',
`is_integral` enum('0','1') COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '0' COMMENT '是否是积分产品',
`created_at` timestamp NULL DEFAULT NULL,
`updated_at` timestamp NULL DEFAULT NULL,
`deleted_at` timestamp NULL DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `order_order_sn_unique` (`order_sn`),
KEY `order_order_sn_member_id_order_status_out_trade_no_index` (`order_sn`,`member_id`,`order_status`,`out_trade_no`(191))
) ENGINE=InnoDB AUTO_INCREMENT=44 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
3. 运输
用户付款结束后接下来就是快递公司的事了,当然咱们不搭理送快递的。到这一步我们就应该给客户展示运输信息。现在一些api开放平台都有快递查询的服务,有收费有免费的,性能方面差异也不大。但这里要注意一点。不是每次用户都会查询到新的信息。对于小公司来说,这样成本极高。所以我们应该定时去查询快递物流信息。这个地方有个简单的算法。
if(用户点击查看了){
从用户点击查看两小时后更新物流信息 // 这里是按照两小时来更新的,也可以拉长这个时间
}else{
每两小时更新一次物流信息
}
这种频繁的更新绝对要使用nosql,当用户确认收货后再存储到mysql等数据库中。
4. 收货
当用户收到货后,这其实是最难伺候的时候,用户对产品的各种不满意就可能导致退换货,收货操作既改变订单状态为已收货,复杂点的可能还需要im,短信,推送提醒下。一般都直接提醒,量大的话加入队列内处理。
5. 退换货
退换货淘宝是这样处理的。 淘宝将订单分两种状态
未付款、已付款、已收货、已评价
发起售后、售后审核、售后处理、处理完成
图1展示了每个商品,包括子商品都可以单独发起售后
图2是点击申请售后之后的页面
图3是选择退换货的相关事项
当完成这些步骤后,就会开启售后审核,卖家审核成功后方可进行下一步操作
5.1 售后申请表
CREATE TABLE `order_returns_apply` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`order_no` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '订单单号',
`order_detail_id` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '子订单编码',
`return_no` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '售后单号',
`member_id` int(11) NOT NULL COMMENT '用户编码',
`state` tinyint(4) NOT NULL COMMENT '类型 0 仅退款 1退货退款',
`product_status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '货物状态 0:已收到货 1:未收到货',
`why` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '退换货原因',
`status` tinyint(4) NOT NULL DEFAULT '0' COMMENT '审核状态 -1 拒绝 0 未审核 1审核通过',
`audit_time` int(11) NOT NULL DEFAULT '0' COMMENT '审核时间',
`audit_why` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '审核原因',
`note` text COLLATE utf8mb4_unicode_ci COMMENT '备注',
`created_at` timestamp NULL DEFAULT NULL,
`updated_at` timestamp NULL DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
5.2 售后表
CREATE TABLE `order_returns` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`returns_no` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '退货编号 供客户查询',
`order_id` int(11) NOT NULL COMMENT '订单编号',
`express_no` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '物流单号',
`consignee_realname` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '收货人姓名',
`consignee_telphone` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '联系电话',
`consignee_telphone2` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '备用联系电话',
`consignee_address` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '收货地址',
`consignee_zip` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '邮政编码',
`logistics_type` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '物流方式',
`logistics_fee` decimal(12,2) NOT NULL COMMENT '物流发货运费',
`order_logistics_status` int(11) DEFAULT NULL COMMENT '物流状态',
`logistics_settlement_status` int(11) DEFAULT NULL COMMENT '物流结算状态',
`logistics_result_last` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '物流最后状态描述',
`logistics_result` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL COMMENT '物流描述',
`logistics_create_time` int(11) DEFAULT NULL COMMENT '发货时间',
`logistics_update_time` int(11) DEFAULT NULL COMMENT '物流更新时间',
`logistics_settlement_time` int(11) DEFAULT NULL COMMENT '物流结算时间',
`returns_type` tinyint(4) NOT NULL DEFAULT '0' COMMENT '0全部退单 1部分退单',
`handling_way` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'PUPAWAY:退货入库;REDELIVERY:重新发货;RECLAIM-REDELIVERY:不要求归还并重新发货; REFUND:退款; COMPENSATION:不退货并赔偿',
`returns_amount` decimal(8,2) NOT NULL COMMENT '退款金额',
`return_submit_time` int(11) NOT NULL COMMENT '退货申请时间',
`handling_time` int(11) NOT NULL COMMENT '退货处理时间',
`remark` text COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '退货原因',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
6. 评价
如果用户收货后直接评价了,那恭喜你,这笔订单基本成交了。这个没什么可讲的,一般小的电商也没有刷评价的,类似淘宝的防止刷评价的做法太过于复杂,这里也不过多讲解(其实我也没接触过)。
6.1 评价数据表
CREATE TABLE `order_appraise` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`order_id` int(11) NOT NULL COMMENT '订单编码',
`info` text COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '评论内容',
`level` enum('-1','0','1') COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '级别 -1差评 0中评 1好评',
`desc_star` tinyint(4) NOT NULL COMMENT '描述相符 1-5',
`logistics_star` tinyint(4) NOT NULL COMMENT '物流服务 1-5',
`attitude_star` tinyint(4) NOT NULL COMMENT '服务态度 1-5',
`created_at` timestamp NULL DEFAULT NULL,
`updated_at` timestamp NULL DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `order_appraise_order_id_index` (`order_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
7. 致谢
感谢你看到这里,希望我的文章和代码可以帮助到你。如果有什么疑问可以在评论区留言,谢谢
如果你对 Dubbo / Netty 等等源码与原理感兴趣,欢迎加入我的知识星球一起交流。长按下方二维码噢:
目前在知识星球更新了《Dubbo 源码解析》目录如下:
01. 调试环境搭建
02. 项目结构一览
03. 配置 Configuration
04. 核心流程一览
05. 拓展机制 SPI
06. 线程池
07. 服务暴露 Export
08. 服务引用 Refer
09. 注册中心 Registry
10. 动态编译 Compile
11. 动态代理 Proxy
12. 服务调用 Invoke
13. 调用特性
14. 过滤器 Filter
15. NIO 服务器
16. P2P 服务器
17. HTTP 服务器
18. 序列化 Serialization
19. 集群容错 Cluster
20. 优雅停机
21. 日志适配
22. 状态检查
23. 监控中心 Monitor
24. 管理中心 Admin
25. 运维命令 QOS
26. 链路追踪 Tracing
... 一共 69+ 篇
目前在知识星球更新了《Netty 源码解析》目录如下:
01. 调试环境搭建
02. NIO 基础
03. Netty 简介
04. 启动 Bootstrap
05. 事件轮询 EventLoop
06. 通道管道 ChannelPipeline
07. 通道 Channel
08. 字节缓冲区 ByteBuf
09. 通道处理器 ChannelHandler
10. 编解码 Codec
11. 工具类 Util
... 一共 61+ 篇
目前在知识星球更新了《数据库实体设计》目录如下:
01. 商品模块
02. 交易模块
03. 营销模块
04. 公用模块
... 一共 17+ 篇
目前在知识星球更新了《Spring 源码解析》目录如下:
01. 调试环境搭建
02. IoC Resource 定位
03. IoC BeanDefinition 载入
04. IoC BeanDefinition 注册
05. IoC Bean 获取
06. IoC Bean 生命周期
... 一共 35+ 篇
源码不易↓↓↓↓↓
点赞支持老艿艿↓↓