本文目录导读:

我来帮你设计一个PHP三级分销佣金计算系统,这个系统将包含完整的数据库结构和计算逻辑。
数据库表结构
-- 用户表
CREATE TABLE users (
id INT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50) NOT NULL,
parent_id INT DEFAULT NULL, -- 上级推荐人ID
level INT DEFAULT 0, -- 用户等级(可选)
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (parent_id) REFERENCES users(id)
);
-- 商品表
CREATE TABLE products (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(100) NOT NULL,
price DECIMAL(10,2) NOT NULL,
commission_rate_1 DECIMAL(5,2) DEFAULT 0.10, -- 一级佣金比例
commission_rate_2 DECIMAL(5,2) DEFAULT 0.05, -- 二级佣金比例
commission_rate_3 DECIMAL(5,2) DEFAULT 0.02 -- 三级佣金比例
);
-- 订单表
CREATE TABLE orders (
id INT PRIMARY KEY AUTO_INCREMENT,
user_id INT NOT NULL, -- 购买用户ID
product_id INT NOT NULL,
price DECIMAL(10,2) NOT NULL, -- 购买价格
status TINYINT DEFAULT 0, -- 订单状态:0待支付,1已支付,2已取消
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id),
FOREIGN KEY (product_id) REFERENCES products(id)
);
-- 佣金记录表
CREATE TABLE commission_records (
id INT PRIMARY KEY AUTO_INCREMENT,
order_id INT NOT NULL,
user_id INT NOT NULL, -- 获得佣金的用户ID
from_user_id INT NOT NULL, -- 产生订单的用户ID
level TINYINT NOT NULL, -- 佣金级别(1,2,3)
amount DECIMAL(10,2) NOT NULL, -- 佣金金额
status TINYINT DEFAULT 0, -- 0待结算,1已结算,2已取消
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (order_id) REFERENCES orders(id),
FOREIGN KEY (user_id) REFERENCES users(id),
FOREIGN KEY (from_user_id) REFERENCES users(id)
);
核心PHP佣金计算类
<?php
class CommissionCalculator {
private $db; // PDO实例
public function __construct(PDO $db) {
$this->db = $db;
}
/**
* 获取用户的上级推荐链(最多三级)
*/
public function getAncestors($userId, $limit = 3) {
$ancestors = [];
$currentId = $userId;
for ($i = 0; $i < $limit; $i++) {
$sql = "SELECT id, parent_id FROM users WHERE id = ?";
$stmt = $this->db->prepare($sql);
$stmt->execute([$currentId]);
$user = $stmt->fetch(PDO::FETCH_ASSOC);
if (!$user || !$user['parent_id']) {
break;
}
$currentId = $user['parent_id'];
$ancestors[] = [
'user_id' => $currentId,
'level' => $i + 1
];
}
return $ancestors;
}
/**
* 计算订单佣金
*/
public function calculateCommission($orderId) {
// 获取订单信息
$orderSql = "SELECT * FROM orders WHERE id = ?";
$orderStmt = $this->db->prepare($orderSql);
$orderStmt->execute([$orderId]);
$order = $orderStmt->fetch(PDO::FETCH_ASSOC);
if (!$order) {
throw new Exception("订单不存在");
}
// 获取商品佣金比例
$productSql = "SELECT * FROM products WHERE id = ?";
$productStmt = $this->db->prepare($productSql);
$productStmt->execute([$order['product_id']]);
$product = $productStmt->fetch(PDO::FETCH_ASSOC);
if (!$product) {
throw new Exception("商品不存在");
}
// 获取购买用户的三级上级
$ancestors = $this->getAncestors($order['user_id'], 3);
// 计算佣金
$commissions = [];
$price = $order['price'];
foreach ($ancestors as $ancestor) {
$level = $ancestor['level'];
// 根据级别获取佣金比例
switch ($level) {
case 1:
$rate = $product['commission_rate_1'];
break;
case 2:
$rate = $product['commission_rate_2'];
break;
case 3:
$rate = $product['commission_rate_3'];
break;
default:
$rate = 0;
}
$amount = round($price * $rate, 2);
if ($amount > 0) {
$commissions[] = [
'order_id' => $orderId,
'user_id' => $ancestor['user_id'],
'from_user_id' => $order['user_id'],
'level' => $level,
'amount' => $amount
];
}
}
return $commissions;
}
/**
* 保存佣金记录(订单支付成功后调用)
*/
public function saveCommissions($orderId) {
// 检查佣金是否已存在
$checkSql = "SELECT COUNT(*) FROM commission_records WHERE order_id = ?";
$checkStmt = $this->db->prepare($checkSql);
$checkStmt->execute([$orderId]);
if ($checkStmt->fetchColumn() > 0) {
throw new Exception("该订单佣金已计算");
}
// 计算佣金
$commissions = $this->calculateCommission($orderId);
// 开启事务
$this->db->beginTransaction();
try {
$insertSql = "INSERT INTO commission_records
(order_id, user_id, from_user_id, level, amount)
VALUES (?, ?, ?, ?, ?)";
$insertStmt = $this->db->prepare($insertSql);
$totalCommission = 0;
foreach ($commissions as $commission) {
$insertStmt->execute([
$commission['order_id'],
$commission['user_id'],
$commission['from_user_id'],
$commission['level'],
$commission['amount']
]);
$totalCommission += $commission['amount'];
}
// 更新订单状态为已支付
$updateOrderSql = "UPDATE orders SET status = 1 WHERE id = ?";
$updateOrderStmt = $this->db->prepare($updateOrderSql);
$updateOrderStmt->execute([$orderId]);
$this->db->commit();
return [
'success' => true,
'total_commission' => $totalCommission,
'details' => $commissions
];
} catch (Exception $e) {
$this->db->rollBack();
throw $e;
}
}
/**
* 取消订单时撤回佣金
*/
public function cancelCommissions($orderId) {
$sql = "UPDATE commission_records SET status = 2 WHERE order_id = ?";
$stmt = $this->db->prepare($sql);
$stmt->execute([$orderId]);
// 更新订单状态为已取消
$updateOrderSql = "UPDATE orders SET status = 2 WHERE id = ?";
$updateOrderStmt = $this->db->prepare($updateOrderSql);
$updateOrderStmt->execute([$orderId]);
return $stmt->rowCount();
}
/**
* 获取用户佣金汇总
*/
public function getUserCommissionSummary($userId) {
$sql = "SELECT
level,
COUNT(*) as order_count,
SUM(amount) as total_amount,
SUM(CASE WHEN status = 0 THEN amount ELSE 0 END) as pending_amount,
SUM(CASE WHEN status = 1 THEN amount ELSE 0 END) as settled_amount
FROM commission_records
WHERE user_id = ?
GROUP BY level";
$stmt = $this->db->prepare($sql);
$stmt->execute([$userId]);
$results = $stmt->fetchAll(PDO::FETCH_ASSOC);
$summary = [
'total' => array_sum(array_column($results, 'total_amount')),
'levels' => []
];
foreach ($results as $row) {
$summary['levels'][] = [
'level' => $row['level'],
'order_count' => $row['order_count'],
'total' => $row['total_amount'],
'pending' => $row['pending_amount'],
'settled' => $row['settled_amount']
];
}
return $summary;
}
/**
* 获取佣金明细列表
*/
public function getCommissionDetail($userId, $page = 1, $pageSize = 20) {
$offset = ($page - 1) * $pageSize;
$sql = "SELECT
cr.*,
u.username as from_user_name,
p.name as product_name
FROM commission_records cr
LEFT JOIN users u ON cr.from_user_id = u.id
LEFT JOIN orders o ON cr.order_id = o.id
LEFT JOIN products p ON o.product_id = p.id
WHERE cr.user_id = ?
ORDER BY cr.created_at DESC
LIMIT $offset, $pageSize";
$stmt = $this->db->prepare($sql);
$stmt->execute([$userId]);
return $stmt->fetchAll(PDO::FETCH_ASSOC);
}
}
使用示例
<?php
// 初始化数据库连接
$dsn = 'mysql:host=localhost;dbname=test;charset=utf8mb4';
$username = 'root';
$password = '';
$options = [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC
];
$db = new PDO($dsn, $username, $password, $options);
$calculator = new CommissionCalculator($db);
// 假设用户注册,建立推荐关系
function registerUser($db, $username, $parentId = null) {
$stmt = $db->prepare("INSERT INTO users (username, parent_id) VALUES (?, ?)");
$stmt->execute([$username, $parentId]);
return $db->lastInsertId();
}
// 创建测试用户
$u1 = registerUser($db, '张总'); // 顶级用户
$u2 = registerUser($db, '李经理', $u1); // 二级用户
$u3 = registerUser($db, '王主管', $u2); // 三级用户
$u4 = registerUser($db, '赵员工', $u3); // 购买者
// 商品佣金设置
$productSql = "INSERT INTO products (name, price, commission_rate_1, commission_rate_2, commission_rate_3)
VALUES ('商品A', 1000.00, 0.10, 0.05, 0.02)";
$db->exec($productSql);
$productId = $db->lastInsertId();
// 创建订单
$orderSql = "INSERT INTO orders (user_id, product_id, price) VALUES (?, ?, ?)";
$stmt = $db->prepare($orderSql);
$stmt->execute([$u4, $productId, 1000.00]);
$orderId = $db->lastInsertId();
// 计算并保存佣金
try {
$result = $calculator->saveCommissions($orderId);
echo "佣金计算成功!\n";
echo "总佣金:{$result['total_commission']} 元\n\n";
foreach ($result['details'] as $detail) {
echo "第{$detail['level']}级佣金:{$detail['amount']} 元(用户ID: {$detail['user_id']})\n";
}
// 查询佣金汇总
echo "\n--- 李经理的佣金汇总 ---\n";
$summary = $calculator->getUserCommissionSummary($u2);
print_r($summary);
// 获取佣金明细
echo "\n--- 佣金明细 ---\n";
$details = $calculator->getCommissionDetail($u2);
foreach ($details as $detail) {
echo "订单:{$detail['product_name']},级别:{$detail['level']},佣金:{$detail['amount']} 元\n";
}
} catch (Exception $e) {
echo "错误:{$e->getMessage()}\n";
}
关键功能说明
佣金计算规则
- 一级佣金:直接推荐人获得10%
- 二级佣金:上级的上级获得5%
- 三级佣金:第三级推荐人获得2%
核心特点
- 自动计算:根据用户关系自动找到三级上级
- 防重复计算:检查佣金记录防止重复计算
- 事务处理:确保数据一致性
- 状态管理:支持待结算、已结算、已取消状态
- 灵活配置:每个商品可独立设置佣金比例
实际应用建议
// 订单支付成功后调用
$calculator->saveCommissions($orderId);
// 订单退货时调用
$calculator->cancelCommissions($orderId);
// 佣金结算
function settleCommissions($userId, $adminId) {
$stmt = $db->prepare("UPDATE commission_records
SET status = 1, settled_at = NOW()
WHERE user_id = ? AND status = 0");
$stmt->execute([$userId]);
// 记录结算操作日志(需要添加settled_at字段)
$logStmt = $db->prepare("INSERT INTO commission_settlements
(user_id, admin_id, amount)
SELECT ?, ?, SUM(amount)
FROM commission_records
WHERE user_id = ? AND status = 0");
$logStmt->execute([$userId, $adminId, $userId]);
}
这个系统提供了完整的函数、安全的事务处理和灵活的可配置性,可以直接用于生产环境,需要根据具体业务需求进行适当调整。