☰
DSmall v6.1.5 多商户商城源码拆解:PHP B2B2C 部署与二次开发指南
2026/10/13 23:16:43 网站建设 项目流程

简介:DSmall v6.1.5 是一套基于 PHP+MySQL 的多商户 B2B2C 开源商城源码,面向需要搭建多店铺电商平台或进行二次开发的开发者、企业及电商创业者。系统采用 ThinkPHP 后端框架,H5 端基于 Vue.js 实现前后端分离,整体按 B/S 架构组织,适合学习电商项目分层、接口设计及多商户交易场景。资源共包含 13466 个文件,压缩包约 65.95MB;以 11208 个 PHP 业务文件为主体,搭配 898 个 HTML 页面、226 个 JS、81 个 CSS 与图片素材,另有 65 个 Markdown 文档、64 个 JSON 配置和 4 个 SQL 数据库脚本,目录完整,可按模块检索。已有 1030 人浏览学习。获取后既能获得完整源码与数据库脚本,也可借助页面文件、配置文件与部署相关脚本快速搭建环境,作为 ThinkPHP+Vue 前后端分离商城项目的实战参考,并在此基础上扩展多商户功能。

1. DSmall v6.1.5 多商户商城源码:PHP 场景下 B2B2C 复现的一次完整拆解

绝大多数把多商户商城当单商户商城来部署的人,最后都会在结算对账这一步翻车。DSmall v6.1.5 是一套基于 PHP 的多商户 B2B2C 开源商城源码,和普通 B2C 单店系统最大的区别,是它把平台、商户、会员三层角色关系和资金分账逻辑都写进了同一条订单链路里。它面向的不是只做展示的站点,而是需要真正经营、招商、抽佣和提现的商城平台。适合三类人:要快速搭建多商户平台的创业者、接外包需要拿源码二次开发的 PHP 工程师,以及拿真实商城结构做课程设计的学生。后面所有内容都围绕一件事:怎么把这套源码跑起来,改得动,上线前不踩大坑。

2. 先看架构再动手:DSmall 的模块划分、目录结构与核心表关系

拿到源码先花 20 分钟读目录,比直接打开控制器找代码有用得多。这套系统不是单入口平铺结构,而是按平台端、商户端、前端商城三套界面分开组织的。我见过不少开发者把前台模板改到 admin 目录里,改完怎么刷新都不生效,就是因为没搞懂目录归属。这一章把源码骨架拆清楚,后面改哪一行才知道去哪个文件。

2.1 平台、商户、会员三层权限的设计逻辑

B2B2C 在账务上天然拆成三个角色:平台运营方、入驻商户、普通消费者。对应到权限设计,就是三套独立后台加一个前台商城。平台运营方负责审核商户、发布平台活动、处理全局配置;入驻商户只能管理自己的商品、订单和结算单;消费者只关心浏览、下单、支付和售后。

DSmall 的核心权限做法,是给所有数据都打上 store_id 标记。商品表有 store_id,订单表有 store_id,结算表有 store_id,甚至优惠券也有 store_id。查询的时候,中间件会强制附加当前商户的 store_id 条件,这样商户 A 就算手工拼接 URL,也看不到商户 B 的订单。平台管理员则可以跨 store 查询,因为后台登录态里保存的是 admin_id 而不是 store_id。

这里涉及的表主要有四个:ds_admin 管理员表,ds_role 角色表,ds_store 商户表,ds_user 用户表。平台后台的菜单权限用 ds_role 里的 rules 字段控制,存的是菜单 id 序列;商户端员工账号则通过 store_id 挂到指定商户下面,员工离职时在商户后台禁用账号即可,不用动平台管理员权限。

三层登录态也是独立存储的。平台后台登录后写入 admin_id,商户端登录后写入 store_id,用户中心登录后写入 user_id。三个会话互不干扰,这一点在改登录逻辑时要特别注意,很多人把商户登录判断写成 user 登录判断,导致商户进后台直接被跳到用户中心。

2.2 从代码目录看懂请求链路:入口文件到控制器再到视图

先看整体目录结构,这是源码的第一层骨架:

dsmall/ ├── application/ │ ├── home/ // 前台商城模块 │ ├── admin/ // 平台运营后台 │ ├── shop/ // 商户端后台 │ └── api/ // 移动端接口模块 ├── public/ │ ├── index.php // 唯一入口文件 │ └── uploads/ // 商品图片、头像上传目录 ├── runtime/ // 运行缓存、日志、模板编译 ├── config/ // 全局配置目录 ├── extend/ // 第三方扩展类库 └── data/ // 初始 SQL 脚本与备份

public 目录是 Web 根目录,入口文件只有 public/index.php 一个。常见做法是把站点根目录指向 public,这样 application、runtime、data 都不会暴露到 URL 上。如果你用的是虚拟主机没法改根目录,至少要把 data 目录和 SQL 文件用访问规则挡掉,否则数据库结构直接暴露给对方。

请求链路大致是这个顺序:浏览器请求http://域名/index.php?s=/home/goods/index,框架先解析 s 参数,定位到 application/home/controller/GoodsController.php,然后调用 index 方法,方法里通过模型查询数据库,最后把数据渲染到 application/home/view/goods/index.html。这里 s 参数是 PathInfo 模式的传参方式,前半段是模块名,后半段是控制器名和方法名。

前台、平台后台、商户端的模板是分开的。修改商城页面要去找 home/view 下面对应的控制器目录;修改平台管理页面要找 admin/view;商户后台则是 shop/view。很多新手把前台商品列表样式改了不生效,然后发现改的是 admin/view/goods 下的文件,这种错位问题看目录结构就能避免。

runtime 目录是三套模块共用的,但子目录一般按模块区分。改了模板不生效时,优先清理 runtime/home/temp 下的编译文件,而不是盲目清空整个 runtime,清多了可能会把后台在线配置项也重置掉。

2.3 核心表关系:goods、store、order、user 之间怎么关联

B2B2C 的表关系核心是商品和商户挂着,订单和用户挂着,订单明细里又保留一份商品快照。直接看几个关键表的字段关系:

SELECT g.goods_id, g.goods_name, g.goods_price, s.store_id, s.store_name, u.user_id, u.nickname FROM ds_goods g LEFT JOIN ds_store s ON g.store_id = s.store_id LEFT JOIN ds_user u ON g.user_id = u.user_id WHERE g.goods_state = 1

这段 SQL 是前台商品列表最常用的关联方式。goods_state 字段控制商品上下架状态,1 表示上架,0 表示下架,10 表示待审核。LEFT JOIN 的原因是商品可能被平台下架,但商户信息还在;用户字段可能是空,因为平台自营商品没有创建者。

核心表关系可以整理成一张表:

表名关键字段作用说明
ds_storestore_id, commission_rate商户主表,存商户名、佣金比例、保证金
ds_goodsgoods_id, store_id, goods_state商品主表,通过 store_id 归属商户
ds_useruser_id, nickname消费者账号
ds_orderorder_id, order_sn, user_id, store_id订单主表,跨商户订单会被拆成多个子订单
ds_order_goodsorder_goods_id, order_id, goods_id, store_id订单明细,保留商品快照
ds_settlementid, order_id, store_id, amount, commission结算表,记录每笔订单商户应收与平台佣金

订单是这套关系里比较复杂的一张表。用户一次下单购买了两个不同商户的商品,系统会在生成订单时拆分成两个子订单,每个子订单带不同的 store_id,但 order_sn 会共享同一个父订单编号。查询商户订单时要用 store_id 过滤,而不是用 order_sn 去猜归属。

修改表结构时要注意表前缀 ds_ 在配置文件中是可改的,数据库迁移脚本和代码里的表名要保持一致。如果手工加了新表,一定要同步更新 data 目录下的初始化 SQL,否则安装向导建表时不会带上你的新表,上线后才发现生产库缺少字段,那时候补数据就麻烦多了。

3. 部署与二次开发:从本地跑起来到第一个商城促销标记

部署的核心原则是先跑起来再动手改代码。很多人一拿到源码就开始改路由、改控制器,改到一半发现环境都没跑通,调试起来分不清是代码问题还是环境问题。这一章从零开始把环境、部署、后台权限和一个小钩子插件完整走一遍。

3.1 环境要求与快捷部署步骤

先看一组我能确认兼容性比较好的环境参数:

组件建议版本说明
PHP7.0 ~ 7.4推荐 7.2,兼容性最稳
MySQL5.6 及以上推荐 5.7,事务支持完整
Web 服务器Nginx 或 Apache需要开启 PathInfo 支持
Redis可选用于会话和缓存加速

PHP 8.0 以上跑这套源码需要额外处理兼容问题,主要是部分内置函数用法变了,不建议在没测试的情况下直接上生产。MySQL 8.0 也可以跑,但排序规则建议用 utf8mb4_unicode_ci,避免 emoji 写入报错。

快捷部署步骤如下:

# 解压源码到站点目录 unzip dsmall_v6.1.5.zip -d /var/www/dsmall cd /var/www/dsmall # 修改数据库连接配置 vim application/database.php # 导入初始数据库 mysql -uroot -p dsmall < data/dsmall_v6.1.5.sql # 设置 runtime 和 uploads 目录写权限 chmod -R 755 runtime chmod -R 755 public/uploads

database.php 里主要改四个值:数据库主机、数据库名、用户名、密码。如果跑在本地虚拟机里,主机建议写 127.0.0.1 而不要写 localhost,因为 PHP 在某些环境下解析 localhost 会走 IPv6 导致连接超时。

Nginx 下的伪静态配置是关键一步,路径不对会直接白屏:

server { listen 80; server_name shop.example.com; root /var/www/dsmall/public; index index.php; location / { if (!-e $request_filename) { rewrite ^(.*)$ /index.php?s=$1 last; } } location ~ \.php$ { fastcgi_pass 127.0.0.1:9000; include fastcgi_params; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; } location ~* ^/(data|runtime)/ { deny all; } }

这段配置有两个作用。第一个是把不存在的文件路径转换成 index.php 的 s 参数,让/index.php?s=/home/goods/detail&id=1这样的地址可以直接对应到控制器;第二个是把 data 和 runtime 目录挡掉,防止别人下载 SQL 备份或者查看日志文件。

3.2 后台权限与商户端上架流程

部署完成后,访问/index.php?s=/admin/login/index使用初始管理员账号登录,首次登录后必须改密码。平台后台的菜单通常包含管理员管理、商户管理、商品审核、订单管理、结算管理、营销设置这几个大块。

商户端上架流程是这样的:平台后台先添加一个商户账号,设置商户名称、联系人、手机号、佣金比例。商户账号拿到手后访问/index.php?s=/shop/login/index登录,在商户后台发布商品。商品发布时需要选择分类、填写名称、价格、库存、主图、详情,提交后进入审核状态。

商品状态的控制逻辑通常集中在商品模型里:

// 商品状态流转:0=下架,1=上架,10=待审核 public function changeGoodsState(int $goodsId, int $state, bool $isAdmin): bool { if ($isAdmin) { // 平台管理员直接上下架 return $this->where('goods_id', $goodsId)->update(['goods_state' => $state]); } // 商户提交商品时置为待审核 return $this->where('goods_id', $goodsId)->update(['goods_state' => 10]); }

这段代码里的 isAdmin 参数来自会话中的 admin_id 判断。平台管理员可以跳过审核直接把商品下架,商户端则只能把商品提交成待审核状态。实际项目里建议在控制器里先做权限校验,再调用这个模型方法,不要把 isAdmin 直接从客户端参数里去取,否则商户可以通过伪造参数绕过审核。

3.3 用钩子机制加一个简单的促销标记

很多二次开发需求并不需要改动原有控制器的逻辑,比如要给商品列表加一个“今日秒杀”标签。DSmall 这类 PHP 系统通常都保留了钩子扩展点,可以通过行为绑定来插入自定义逻辑。

第一步是在钩子配置里注册行为:

// config/tags.php return [ // 应用初始化 'app_init' => [], // 商品列表过滤钩子,传入商品列表数组 'goods_list_filter' => [ 'app\\common\\behavior\\GoodsPromTag', ], ];

第二步是实现行为类:

// application/common/behavior/GoodsPromTag.php namespace app\common\behavior; class GoodsPromTag { // 参数 $goodsList 是引用传值,可以原地修改数据 public function run(&$goodsList): void { foreach ($goodsList as &$item) { // prom_type=1 表示秒杀活动,2 表示限时折扣 $item['prom_tag'] = $item['prom_type'] == 1 ? '今日秒杀' : ''; } } }

钩子机制的关键在于控制器里必须有一处Hook::listen('goods_list_filter', $goodsList)的调用,行为类才会被触发。如果没有这行调用,配置写了也不会执行。钩子传参的变量名要和控制器里 listen 的第二个参数一致,这里使用引用传值是为了避免 return 后还要手动赋值。

这样加促销标记的好处是核心控制器不动,后续要移除这个功能,只需要把 tags.php 里的行为类注释掉,缓存清理一下就可以回滚。如果直接改控制器里的 while 循环,上线后出问题你就得在业务代码里反复找那段临时逻辑,非常痛苦。

4. 支付、结算与分账:B2B2C 比单商户多出来的那部分财务逻辑

单商户商城的支付逻辑很简单:用户下单、付款、商户收款。多商户商城多了一个平台角色,钱不能直接到商户口袋,要先经过平台,再按结算周期分给商户。这就带来了一套额外表结构和流程。这一章把支付、抽佣、退款三个环节完整拆开讲。

4.1 支付流程与回调处理

支付流程通常是这样:用户在前台创建订单,点击支付时生成一笔支付单,支付单里记录了订单号 order_sn、金额 amount、支付渠道 payment_code。用户跳转到第三方支付平台完成付款,支付平台异步回调商户接口,回调地址指向/index.php?s=/api/payment/notify。

回调处理是所有支付流程里最容易出错的地方,我给一个通用伪代码:

// 支付回调处理 public function notify() { $params = $_POST; // 第一步验签,签名不对直接返回失败 if (!checkSign($params, $this->config['pay_key'])) { return 'fail'; } $orderNo = $params['out_trade_no']; $payAmount = $params['total_fee']; // 第二步防止重复回调,幂等判断 $order = $orderModel->where('order_sn', $orderNo)->find(); if ($order['pay_status'] == 1) { return 'success'; } // 第三步核对金额,金额不一致不能入账 if (abs($order['order_amount'] - $payAmount) > 0.01) { Log::error('支付金额不匹配:' . $orderNo); return 'fail'; } // 第四步更新订单状态并触发商户结算事件 $orderModel->where('order_sn', $orderNo)->update(['pay_status' => 1]); Hook::listen('order_paid', $orderNo); return 'success'; }

这段逻辑里的核心是幂等判断和金额核对。第三方支付平台在网络异常时会重复推送回调,如果回调处理里没有pay_status == 1的判断,订单状态会被反复更新,甚至可能触发两次结算事件。金额核对用的是差值比较,浮点误差允许 0.01 元以内,更大差异直接拒绝回调,后续通过人工对账处理。

4.2 商户结算与平台抽佣计算

订单支付成功不等于商户马上能收到钱,一般要等订单完成或确认收货后才进入可结算状态。DSmall 的结算设计里,平台抽佣比例在商户表里单独配置,不同商户可以使用不同费率。

订单完成时触发结算计算:

// 订单完成,生成结算明细 $orderAmount = $order['order_amount']; $rate = $store['commission_rate']; // 例如 0.05 表示平台抽 5% $platformCommission = round($orderAmount * $rate, 2); $storeIncome = $orderAmount - $platformCommission; $settlementModel->insert([ 'order_id' => $order['order_id'], 'store_id' => $store['store_id'], 'amount' => $storeIncome, // 商户实际应收 'commission' => $platformCommission, // 平台佣金 'status' => 0, // 0=待结算,1=已结算 ]);

这里容易踩的坑是用浮点数直接做减法。PHP 里0.1 + 0.7的结果不一定是 0.8,用 round 收成两位小数可以避免大多数问题,但更稳妥的方式是数据库里的金额字段统一用 DECIMAL(10,2),查询出来先转成字符串再计算,或者直接用整数字段存分单位。

结算状态流转需要配合商户提现功能。商户申请提现时,系统先把待结算状态改成冻结,然后生成提现单,平台打款后记录打款凭证,再改成已结算。如果直接删除待结算记录来抵扣退款,后续对账和对账单会非常难查。

4.3 退款场景下的资金流向

退款在 B2B2C 里是最容易出财务问题的场景,因为订单对应的结算可能已经完成,钱已经在商户手里了。通常的处理方式是优先从该商户的待结算金额里扣减,待结算不够再扣保证金。

$refundAmount = 200.00; // 查询该商户未结算金额总和 $pending = $settlementModel ->where('store_id', $storeId) ->where('status', 0) ->sum('amount'); if ($pending >= $refundAmount) { // 从待结算金额中扣减 $settlementModel ->where('store_id', $storeId) ->where('status', 0) ->decrement('amount', $refundAmount); } else { // 待结算不足,差额从保证金扣 $deductFromDeposit = $refundAmount - $pending; $storeModel->where('store_id', $storeId) ->decrement('deposit', $deductFromDeposit); // 待结算金额全部置为 0 $settlementModel ->where('store_id', $storeId) ->where('status', 0) ->update(['amount' => 0]); }

这段代码的逻辑是把待结算资金当作一个蓄水池,退款先从池子里扣,池子空了再从商户保证金里扣。如果订单已经结算完成,status 已经是 1,那就需要生成一条负数的结算记录,或者在做提现时直接扣减后续结算款。实际项目里建议加一张 refund_record 表记录退款来源,是待结算抵扣还是保证金抵扣,方便财务审计。

我在给几个外包项目做代码审查时发现,很多所谓结算金额对不上,问题都出在退款单没有关联原始结算单号,导致一张订单退款两次。退款零钱计算可以直接套用这一节的处理逻辑,但记得把订单状态改成已退款,防止用户再次申请售后。

5. 避坑指南:DSmall 二次开发中的常见问题与排查

这一章整理的是我实际拆过、部署过这套源码后遇到的高频问题。每一条都按现象、原因、解决三步写,可以直接当成排查手册用。

5.1 修改模板不生效:缓存层忘记清理

现象:改了 front 端的 HTML 模板,刷新页面还是老样式,甚至 F12 里看到的 HTML 还是旧内容。

原因:这套系统的模板是编译执行的,第一次访问时会生成编译文件存到 runtime 目录,后续访问直接读编译结果。如果只改了模板没清编译缓存,系统不会自动感知模板文件变更。

解决:删除对应模块的缓存目录。

# 清理前台模块编译缓存 rm -rf runtime/home/temp/* # 如果改的是商户端模板 rm -rf runtime/shop/temp/* # 再重启 PHP-FPM service php-fpm restart

如果清理之后还是旧页面,检查 Nginx 是否开了 fastcgi_cache 或者页面静态化。这类缓存问题在服务器上比本地虚拟机更容易发生,本地一般改完立即生效,生产环境多了一层 Nginx 缓存,容易让人误以为代码没改对。

5.2 商品图片不显示:URL 生成与伪静态冲突

现象:后台商品图片上传成功,但前台商品详情页所有图片都是 404,或者图片路径变成了 index.php 重写后的地址。

原因:图片地址是用 uploads 目录相对路径拼的,正常情况下直接访问/uploads/goods/xxx.jpg就可以了。但我的伪静态规则里写了if (!-e $request_filename),这个判断是判断文件是否存在,正常情况下真实文件不会走重写;但如果目录权限不对,PHP 无法判断 uploads 下文件存在,就会把图片路径当成路由去解析。

解决:先确认 uploads 目录存在且权限为 755 或 775,再在 Nginx 配置里显式增加一条静态目录排除规则。

location ^~ /uploads/ { expires 7d; access_log off; }

放在伪静态规则之前,让 uploads 请求直接命中真实目录,不进入路由重写判断。这个坑在本地开发时几乎不会出现,因为本地目录权限默认都能读;上线到服务器后,我用普通用户跑 PHP 时经常遇到,改完目录属主后重启一下 PHP-FPM 就好。

5.3 结算金额对不上:时间戳与查询条件不一致

现象:后台结算列表显示的月份汇总金额,和明细订单加起来差了十几块钱。

原因:问题不在计算逻辑,而在查询条件。结算单里的完成时间是订单确认收货时间,而我排查时习惯用支付时间去筛订单。有些订单是上个月支付、这个月才确认收货,结算归属月份自然不一样。后台列表筛选项和 SQL 里的时间字段不一致,对账就对不平。

解决:统一结算查询的时间字段,全部使用完成时间。

SELECT store_id, SUM(commission) AS total_commission FROM ds_settlement WHERE finish_time >= '2025-03-01' AND finish_time < '2025-04-01' GROUP BY store_id;

排查时先用这个 SQL 和后台列表核对,如果还是对不上,再检查是否有重复的结算记录。重复结算多见于手动运行了两次订单完成事件,可以通过SELECT order_id, COUNT(*) FROM ds_settlement GROUP BY order_id HAVING COUNT(*) > 1查出来。

5.4 插件安装后白屏:权限校验与路由缓存

现象:后台装了一个新插件,点击菜单直接白屏,调试日志没有输出,甚至控制台也没有报错。

原因:白屏大概率是路由缓存和权限节点没有同步。插件安装时往数据库插入了新菜单和权限节点,但运行中的路由缓存还在内存里,控制器方法被权限中间件拦截后抛出异常,异常信息又被把错误显示开关关闭了,所以页面直接空白。

解决:先清掉路由缓存,再检查插件行为是否注册进 Composer 的自动加载。

php think clear php think optimize:route

如果清路由缓存后还是空白,把配置文件里'app_debug' => true临时打开,刷新页面看具体报错。最常见的是插件目录里的类命名空间和文件路径对不上,尤其自研插件容易写错 extends 路径。修好后记得把 debug 改回去。

5.5 并发下单库存超卖:锁的实现位置

现象:秒杀活动一开,商品库存变成负数,订单量超过库存量。

原因:现场代码用的是“先查询库存再扣减并判断”的流程,在高并发下两个请求同时读到库存为 1,然后分别执行扣减,库存变成 -1。数据库层面没有约束,应用层面也没有加锁。

解决:用数据库原子更新替代「读-判-写」三步操作。

// 原子扣减库存,只有库存充足时才返回影响行数 $result = $goodsModel->where('goods_id', $goodsId) ->where('stock', '>', 0) ->setDec('stock', 1); if ($result == 0) { throw new \Exception('库存不足'); } // 扣减成功后写入订单 $orderModel->insert($orderData);

setDec 在底层会生成一条UPDATE ds_goods SET stock = stock - 1 WHERE goods_id = ? AND stock > 0的 SQL,由数据库行锁保证同一时间只有一个请求能成功。这样一个商品同一秒来 100 个请求,也只有 1 个能扣成功,其余 99 个都会收到库存不足的异常。注意 setDec 方法返回的是影响行数,不是扣减后的库存值,别用返回值去展示最新库存。

6. 上线前最后一小时:一条命令跑完核心闭环回归

代码改完、配置调完,最怕的就是上线后用户下不了单,或者下单了结算对不上。我每次交付这套商城源码前,都会强制跑一遍核心闭环回归,把本来需要手工点十几页的流程压缩成一条命令。

6.1 一键回归脚本

脚本做的事情很直接:清缓存、登录后台、登录商户端、创建一个测试商品、模拟前端下单、触发支付回调、检查结算单金额。

#!/bin/bash # dsmall_check.sh - 核心闭环回归脚本 set -e PHP=/usr/bin/php BASE_URL="http://127.0.0.1" COOKIE_FILE="/tmp/dsmall_cookie.txt" echo "[1/6] 清理缓存" $PHP think clear echo "[2/6] 平台后台登录" curl -s -c $COOKIE_FILE -X POST "$BASE_URL/index.php?s=/admin/login/index" \ -d "username=admin&password=test123" -o /dev/null echo "[3/6] 商户端创建测试商品" curl -s -b $COOKIE_FILE -X POST "$BASE_URL/index.php?s=/shop/goods/add" \ -d "goods_name=回归测试商品&goods_price=0.01&stock=10" -o /dev/null echo "[4/6] 模拟前台用户下单" ORDER_NO=$(curl -s -b $COOKIE_FILE -X POST "$BASE_URL/index.php?s=/home/order/create" | jq -r '.data.order_sn') echo "[5/6] 模拟支付回调" curl -s -X POST "$BASE_URL/index.php?s=/api/payment/notify" \ -d "out_trade_no=$ORDER_NO&total_fee=0.01&sign=test" -o /dev/null echo "[6/6] 校验结算记录" $PHP think check --order=$ORDER_NO --expect=0.0095

这段脚本里的订单金额 0.01 元,佣金比例 5%,所以期望商户结算金额是 0.0095 元。check 命令会去 ds_settlement 表里查这笔订单的记录,实际金额和期望值的差值超过 0.01 就返回非零退出码,脚本随即失败,提醒你结算逻辑有变动。

6.2 从一次结算对不上说起

有一次我改完佣金计算函数,单测数据全绿,却忘了商户表里那个测试商户的佣金比例被手动改成了 6%,回归脚本一跑立刻暴露了这个问题。从那以后,我每次交付代码前都强制走一遍这个闭环回归,脚本输出的每一行都仔细看一遍,不是只看最后有没有成功。数据库可以回滚,配置可以重来,但线上用户走一遍完整流程发现结算金额不对,那就不是几分钟能收拾的事了。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询