当前位置:网站首页 >  教程

全域佣金分成从零搭建实操指南 覆盖规则配置到数据核算全流程

时间:2026年05月31日 04:57:28 来源:易频IT社区

一、前置准备

1.1 环境依赖安装

本次搭建采用Node.js + MySQL 技术栈,所有依赖可直接执行以下命令安装:

``` 安装Node.js 16.x版本(官方稳定版) Windows下载地址:https://nodejs.org/dist/v16.20.2/node-v16.20.2-x64.msi macOS/Linux执行:curl -fsSL https://rpm.nodesource.com/setup_16.x | bash - && yum install -y nodejs 安装项目依赖 npm install koa2 mysql2 dayjs @koa/router --save ```

1.2 数据库初始化

直接执行以下SQL创建核心表,可直接复制到MySQL客户端运行:

```sql CREATE DATABASE IF NOT EXISTS commission_system DEFAULT CHARSET utf8mb4; USE commission_system; -- 角色钱包表 CREATE TABLE `user_wallet` ( `id` int unsigned NOT NULL AUTO_INCREMENT, `user_id` varchar(32) NOT NULL COMMENT '用户ID', `role` tinyint NOT NULL COMMENT '1=品牌方 2=代理商 3=团长 4=推广员', `balance` decimal(10,4) NOT NULL DEFAULT '0.0000' COMMENT '可用余额', `freeze_amount` decimal(10,4) NOT NULL DEFAULT '0.0000' COMMENT '冻结金额', PRIMARY KEY (`id`), UNIQUE KEY `user_id` (`user_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- 订单表 CREATE TABLE `order_info` ( `id` int unsigned NOT NULL AUTO_INCREMENT, `order_sn` varchar(32) NOT NULL COMMENT '订单号', `pay_amount` decimal(10,2) NOT NULL COMMENT '实付金额', `status` tinyint NOT NULL COMMENT '0=取消 1=待发货 2=已发货 3=已完成 4=已退款', `finish_time` int DEFAULT NULL COMMENT '确认收货时间戳', `is_settled` tinyint NOT NULL DEFAULT '0' COMMENT '0=未分账 1=已分账', PRIMARY KEY (`id`), UNIQUE KEY `order_sn` (`order_sn`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; -- 分账记录表 CREATE TABLE `commission_log` ( `id` int unsigned NOT NULL AUTO_INCREMENT, `order_sn` varchar(32) NOT NULL COMMENT '订单号', `user_id` varchar(32) NOT NULL COMMENT '分账用户ID', `role` tinyint NOT NULL COMMENT '用户角色', `amount` decimal(10,4) NOT NULL COMMENT '分账金额', `settle_time` int NOT NULL COMMENT '分账时间戳', `status` tinyint NOT NULL DEFAULT '0' COMMENT '0=待发放 1=已发放 2=已回滚', PRIMARY KEY (`id`), KEY `order_sn` (`order_sn`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; ```

二、核心分账规则配置

在项目根目录新建config/commission.js文件,复制以下完整配置,可根据自身业务调整比例:

```javascript module.exports = { // 总佣金占订单实付金额比例 totalCommissionRate: 0.15, // 各角色分账比例(占总佣金的比例,总和必须为1) roleRate: { 1: 0.3, // 品牌方30% 2: 0.25, // 代理商25% 3: 0.2, // 团长20% 4: 0.25 // 推广员25% }, // 分账触发条件 triggerCondition: { // 订单完成后等待天数(过7天无理由退换期) waitDays: 7, // 排除的订单状态 excludeStatus: [0,4] }, // 数据库配置,替换为自己的数据库信息 db: { host: '127.0.0.1', port: 3306, user: 'root', password: '你的数据库密码', database: 'commission_system' } } ```

注意:各角色分账比例总和必须严格等于1,否则会出现分账金额与总佣金不符的问题

三、实时佣金计算接口开发

在项目根目录新建routes/settle.js文件,复制以下完整代码,接口可直接调用:

```javascript const Router = require('@koa/router'); const router = new Router({ prefix: '/api/commission' }); const dayjs = require('dayjs'); const mysql = require('mysql2/promise'); const config = require('../config/commission'); const db = mysql.createPool(config.db); // 订单分账接口 router.post('/settle', async (ctx) => { const { order_sn } = ctx.request.body; // 校验参数 if (!order_sn) { ctx.body = { code: 400, msg: '订单号不能为空' }; return; } // 查询订单信息 const [order] = await db.query('SELECT FROM order_info WHERE order_sn = ?', [order_sn]); if (!order || order.length === 0) { ctx.body = { code: 404, msg: '订单不存在' }; return; } const orderInfo = order[0]; // 校验订单状态 if (config.triggerCondition.excludeStatus.includes(orderInfo.status)) { ctx.body = { code: 400, msg: '订单状态不允许分账' }; return; } // 校验是否已分账 if (orderInfo.is_settled === 1) { ctx.body = { code: 400, msg: '订单已分账' }; return; } // 校验是否过了等待期 if (dayjs().unix() - orderInfo.finish_time < config.triggerCondition.waitDays 86400) { ctx.body = { code: 400, msg: '订单未过解冻期,暂无法分账' }; return; } // 计算总佣金 const totalCommission = parseFloat((orderInfo.pay_amount config.totalCommissionRate).toFixed(4)); // 开启事务 const conn = await db.getConnection(); await conn.beginTransaction(); try { // 按角色分账 for (let role in config.roleRate) { const amount = parseFloat((totalCommission config.roleRate[role]).toFixed(4)); // 查询对应角色用户ID,此处可根据自身业务的绑定关系替换查询逻辑 const [user] = await conn.query('SELECT user_id FROM user_wallet WHERE role = ? LIMIT 1', [role]); if (user.length > 0) { const userId = user[0].user_id; // 写入分账记录 await conn.query('INSERT INTO commission_log (order_sn, user_id, role, amount, settle_time) VALUES (?, ?, ?, ?, ?)', [order_sn, userId, role, amount, dayjs().unix()]); // 更新用户钱包 await conn.query('UPDATE user_wallet SET balance = balance + ? WHERE user_id = ?', [amount, userId]); } } // 更新订单分账状态 await conn.query('UPDATE order_info SET is_settled = 1 WHERE order_sn = ?', [order_sn]); await conn.commit(); ctx.body = { code: 200, msg: '分账成功' }; } catch (e) { await conn.rollback(); ctx.body = { code: 500, msg: '分账失败', error: e.message }; } finally { conn.release(); } }); module.exports = router; ```

全域佣金分成从零搭建实操指南 覆盖规则配置到数据核算全流程

必须开启事务处理分账逻辑,避免分账过程中出现异常导致数据不一致

四、对账核销操作流程

4.1 日终自动对账脚本

在项目根目录新建script/check.js,配置crontab每天凌晨1点执行,脚本内容如下:

```javascript const mysql = require('mysql2/promise'); const dayjs = require('dayjs'); const config = require('../config/commission'); const db = mysql.createPool(config.db); async function checkDailySettle() { const startTime = dayjs().subtract(1, 'day').startOf('day').unix(); const endTime = dayjs().subtract(1, 'day').endOf('day').unix(); // 查询当日分账总金额 const [totalRes] = await db.query('SELECT SUM(amount) as total FROM commission_log WHERE settle_time BETWEEN ? AND ? AND status = 1', [startTime, endTime]); const totalSettle = parseFloat(totalRes[0].total || 0).toFixed(2); // 查询支付渠道打款总金额,此处替换为你对接的支付渠道查询接口 // const payTotal = await payApi.queryTransferTotal(startTime, endTime); const payTotal = 0; // 测试用,实际替换为接口返回值 // 差异校验 if (Math.abs(totalSettle - payTotal) > 0.01) { // 触发告警,可接入企业微信/钉钉机器人 console.log(`日终对账异常,分账总金额:${totalSettle},打款总金额:${payTotal}`); } else { console.log('日终对账正常'); } } checkDailySettle(); ```

crontab配置命令:0 1 /usr/local/bin/node /你的项目路径/script/check.js >> /var/log/commission_check.log 2>&1

4.2 人工复核步骤

  • 1. 登录后台导出前一日的commission_log表数据,筛选status=1的记录
  • 2. 导出支付渠道的打款流水,按订单号逐一匹配,核对金额是否一致
  • 3. 所有记录核对无误后,批量标记分账记录为已核销状态
  • 4. 存在差异的记录标记为异常,进入异常处理流程

五、异常场景处理方案

5.1 重复分账处理

首先冻结对应分账用户的待提现金额,执行以下SQL:

```sql UPDATE user_wallet SET freeze_amount = freeze_amount + 重复分账金额 WHERE user_id = '对应用户ID'; ```

如果用户余额充足,直接扣除对应金额:UPDATE user_wallet SET balance = balance - 重复分账金额, freeze_amount = freeze_amount - 重复分账金额 WHERE user_id = '对应用户ID';,同时删除对应重复的分账记录,更新订单is_settled状态为0。

5.2 订单退款回滚

  • 若分账未实际打款:直接删除对应分账记录,更新用户钱包余额,将订单状态标记为已退款
  • 若分账已打款:优先从用户待提现余额扣除对应金额,余额不足的标记为坏账,按月度统一结算

相关推荐

最新

热门

推荐

精选

标签

易频IT社区是综合性互联网IT技术门户网站,专注分享网络技术、服务器运维、网络安全、编程开发、系统架构、云计算、大数据等行业干货,实时更新IT行业资讯、零基础教程、实战案例,为IT从业者、技术爱好者提供专业的学习交流平台。

Copyright © 2021-2026 易频IT社区. All Rights Reserved. 备案号:闽ICP备2023013482号 网站地图