Commit 565f792d authored by 刘小敏's avatar 刘小敏

feat(commission): 支持补漏已支付订单的分佣及代理绑定

parent 8c0ecfc3
......@@ -10,21 +10,27 @@ use app\admin\model\shopro\commission\Order as CommissionOrderModel;
use app\admin\model\shopro\commission\Reward as RewardModel;
use addons\shopro\service\commission\Order as OrderService;
use addons\shopro\service\commission\Reward as RewardService;
use addons\shopro\service\commission\Agent as AgentService;
/**
* 补漏分销商分佣脚本
*
* 遍历已完成的订单,检查分销佣金是否遗漏,补全数据:
* 遍历已完成/已支付的订单,检查分销佣金是否遗漏,补全数据:
* 1. 对于完全没有分佣订单记录的商品,模拟"订单支付成功"流程
* 创建 commission_order + commission_reward
* 2. 对于已有分佣记录但佣金状态为"未结算"的,模拟"订单完成"流程
* 执行奖励拨款(使用 admin 事件,绕过 reward_event 匹配限制)
* 创建 commission_order + commission_reward(含佣金流水日志)
* 2. 对于已支付订单,补全代理绑定、分销商创建等支付后逻辑
* 3. 对于已有分佣记录但佣金状态为"未结算"的:
* - 已完成订单: 使用 admin 事件结算(绕过 reward_event 匹配限制)
* - 已支付订单: 使用 paid 事件尝试结算(遵守系统配置)
*
* 命令:php think shopro:fix-missed-commission
* php think shopro:fix-missed-commission --order_id=123 (指定订单)
* php think shopro:fix-missed-commission --order_id=123 (指定订单)
* php think shopro:fix-missed-commission --status=paid (只处理已支付订单)
* php think shopro:fix-missed-commission --status=all (处理已支付+已完成)
*
* 使用场景:
* - 历史订单漏掉分销商分佣时,一次性补填数据
* - 支付后脚本异常导致佣金记录/代理绑定/分销商创建遗漏
* - 可重复执行,已结算的记录不会重复打款
*/
class FixMissedCommission extends Command
......@@ -46,8 +52,9 @@ class FixMissedCommission extends Command
protected function configure()
{
$this->setName('shopro:fix-missed-commission')
->setDescription('补漏分销商分佣:遍历已完成订单,补充遗漏的分销佣金记录并结算')
->addOption('order_id', null, Option::VALUE_OPTIONAL, '指定订单ID(只处理该订单)', null);
->setDescription('补漏分销商分佣:遍历已完成/已支付订单,补充遗漏的分销佣金记录并结算')
->addOption('order_id', null, Option::VALUE_OPTIONAL, '指定订单ID(只处理该订单)', null)
->addOption('status', null, Option::VALUE_OPTIONAL, '订单状态: paid(已支付) / completed(已完成) / all(全部)', 'completed');
}
/**
......@@ -91,7 +98,15 @@ class FixMissedCommission extends Command
// 指定订单ID(可选参数)
$specifiedOrderId = $input->getOption('order_id');
// 订单状态过滤
$statusFilter = $input->getOption('status');
if (!in_array($statusFilter, ['paid', 'completed', 'all'])) {
$statusFilter = 'completed';
}
$statusName = ['paid' => '已支付', 'completed' => '已完成', 'all' => '已支付+已完成'][$statusFilter];
$this->customLog('info', '========== 开始补漏分销商分佣 ==========');
$this->customLog('info', "订单状态过滤: {$statusName}");
if ($specifiedOrderId) {
$this->customLog('info', "指定订单模式: 仅处理订单[{$specifiedOrderId}]");
}
......@@ -111,14 +126,20 @@ class FixMissedCommission extends Command
$noActionDetails = []; // 无需处理: "订单ID[order_sn] 原因"
while (true) {
// 分页查询已完成的订单(排除积分商品订单 + 已软删除订单)
// 分页查询已支付/已完成的订单(排除积分商品订单 + 已软删除订单)
$query = Db::name('shopro_order')
->where('status', 'completed')
->where('type', '<>', 'score')
->whereNull('deletetime')
->field('id, user_id, order_sn, deduct_score')
->field('id, user_id, order_sn, deduct_score, status')
->order('id', 'asc');
// 按状态过滤
if ($statusFilter === 'all') {
$query->whereIn('status', ['paid', 'completed']);
} else {
$query->where('status', $statusFilter);
}
if ($specifiedOrderId) {
$query->where('id', $specifiedOrderId);
} else {
......@@ -129,7 +150,7 @@ class FixMissedCommission extends Command
if (empty($orders)) {
if ($specifiedOrderId) {
$this->customLog('error', "订单[{$specifiedOrderId}]不存在或状态不是已完成(可能已软删除、非商品订单、或未完成)");
$this->customLog('error', "订单[{$specifiedOrderId}]不存在或不满足当前状态条件(状态需为{$statusName},且未软删除、非积分商品订单)");
} else {
$this->customLog('info', "第{$page}页无数据,遍历结束");
}
......@@ -138,14 +159,51 @@ class FixMissedCommission extends Command
$pageTotal = count($orders);
$totalOrders += $pageTotal;
$this->customLog('info', "第{$page}页: 获取 {$pageTotal}已完成订单");
$this->customLog('info', "第{$page}页: 获取 {$pageTotal}{$statusName}订单");
foreach ($orders as $order) {
$orderId = $order['id'];
$orderUserId = $order['user_id'];
$orderSn = $order['order_sn'] ?? '';
$orderStatus = $order['status'] ?? '';
$isPaidOrder = ($orderStatus === 'paid');
$deductScore = isset($order['deduct_score']) ? intval($order['deduct_score']) : 0;
// ===== 已支付订单:补全支付后的代理绑定/分销商创建流程 =====
if ($isPaidOrder) {
try {
$agentService = new AgentService($orderUserId);
// 绑定用户关系(上级代理绑定)
$bindResult = $agentService->bindUserRelation('pay');
if ($bindResult) {
$this->customLog('info', "订单[{$orderId}][{$orderSn}] ✓ 支付后代理绑定成功");
} else {
$this->customLog('info', "订单[{$orderId}][{$orderSn}] - 代理绑定跳过(已有上级或不满足绑定条件)");
}
// 创建分销商(满足条件则自动创建)
$agentStatus = $agentService->createNewAgent();
$agentStatusMap = [
'normal' => '已创建(正常)',
'pending' => '已创建(待审核)',
'needinfo' => '需补充资料',
'reject' => '已拒绝',
'freeze' => '已冻结',
'forbidden'=> '已禁用',
];
$agentStatusText = $agentStatusMap[$agentStatus] ?? ($agentStatus === null ? '不满足条件' : "状态[{$agentStatus}]");
$this->customLog('info', "订单[{$orderId}][{$orderSn}] 分销商创建: {$agentStatusText}");
// 异步升级任务(已创建或已有分销商身份时触发)
if ($agentStatus !== null) {
$agentService->createAsyncAgentUpgrade();
}
} catch (\Exception $e) {
$this->customLog('warn', "订单[{$orderId}][{$orderSn}] 代理绑定/创建异常: " . $e->getMessage());
}
}
// 获取订单下所有未退款的商品
$items = Db::name('shopro_order_item')
->where('order_id', $orderId)
......@@ -160,7 +218,8 @@ class FixMissedCommission extends Command
continue;
}
$this->customLog('info', "━━━ 订单[{$orderId}][{$orderSn}]开始处理 ━━━ 商品数:" . count($items) . " 用户ID:{$orderUserId}" . ($deductScore > 0 ? " 积分抵扣:{$deductScore}" : ""));
$statusTag = $isPaidOrder ? '[已支付]' : '[已完成]';
$this->customLog('info', "━━━ {$statusTag}订单[{$orderId}][{$orderSn}]开始处理 ━━━ 商品数:" . count($items) . " 用户ID:{$orderUserId}" . ($deductScore > 0 ? " 积分抵扣:{$deductScore}" : ""));
// 积分抵扣部分需按比例从佣金基数中扣除
$scoreDeductAmount = $deductScore > 0 ? round($deductScore / 100, 2) : 0;
......@@ -263,7 +322,7 @@ class FixMissedCommission extends Command
// 第一步小结
$this->customLog('info', " └─ 第一步完成: 新建{$orderStep1Created}条, 跳过{$orderStep1Skipped}条");
// 第二步:对订单下所有未结算的分销奖励执行拨款(模拟订单完成流程)
// 第二步:对订单下所有未结算的分销奖励执行拨款
$commissionOrders = CommissionOrderModel::where('order_id', $orderId)->select();
if (empty($commissionOrders)) {
$totalNoAction++;
......@@ -272,11 +331,13 @@ class FixMissedCommission extends Command
continue;
}
$this->customLog('info', " ├─ 第二步开始: 共" . count($commissionOrders) . "条分销订单待结算");
// 已支付订单用 paid 事件(遵守系统配置),已完成订单用 admin 事件(强制结算)
$settlementEvent = $isPaidOrder ? 'paid' : 'admin';
$this->customLog('info', " ├─ 第二步开始: 共" . count($commissionOrders) . "条分销订单待结算 (事件:{$settlementEvent})");
$orderStep2Settled = 0;
$orderStep2Skipped = 0;
$rewardService = new RewardService('admin'); // admin 事件不限制 reward_event
$rewardService = new RewardService($settlementEvent);
foreach ($commissionOrders as $co) {
$statusText = '';
switch ($co['commission_reward_status']) {
......@@ -333,14 +394,15 @@ class FixMissedCommission extends Command
$this->customLog('info', " └─ 第二步完成: 结算{$orderStep2Settled}条, 跳过{$orderStep2Skipped}条");
// 订单处理小结
$statusTag = $isPaidOrder ? '[已支付]' : '[已完成]';
if ($orderStep1Created > 0 || $orderStep2Settled > 0) {
$this->customLog('info', "━━━ 订单[{$orderId}][{$orderSn}]处理完成 ✓ 新建:{$orderStep1Created} 结算:{$orderStep2Settled} 跳过:{$orderStep1Skipped}+{$orderStep2Skipped} ━━━");
$this->customLog('info', "━━━ {$statusTag}订单[{$orderId}][{$orderSn}]处理完成 ✓ 新建:{$orderStep1Created} 结算:{$orderStep2Settled} 跳过:{$orderStep1Skipped}+{$orderStep2Skipped} ━━━");
} elseif ($orderStep2Skipped > 0) {
$this->customLog('info', "━━━ 订单[{$orderId}][{$orderSn}]处理完成 - 已有分佣已结算,跳过:{$orderStep1Skipped}+{$orderStep2Skipped} ━━━");
$this->customLog('info', "━━━ {$statusTag}订单[{$orderId}][{$orderSn}]处理完成 - 已有分佣已结算,跳过:{$orderStep1Skipped}+{$orderStep2Skipped} ━━━");
} else {
$totalNoAction++;
$noActionDetails[] = "订单[{$orderId}][{$orderSn}] 原因: 所有商品已有分佣记录或无分销条件";
$this->customLog('info', "━━━ 订单[{$orderId}][{$orderSn}]处理完成 - 无新操作(无需处理),跳过:{$orderStep1Skipped}+{$orderStep2Skipped} ━━━");
$noActionDetails[] = "{$statusTag}订单[{$orderId}][{$orderSn}] 原因: 所有商品已有分佣记录或无分销条件";
$this->customLog('info', "━━━ {$statusTag}订单[{$orderId}][{$orderSn}]处理完成 - 无新操作(无需处理),跳过:{$orderStep1Skipped}+{$orderStep2Skipped} ━━━");
}
}
......@@ -354,8 +416,11 @@ class FixMissedCommission extends Command
}
$this->customLog('info', "========== 汇总统计 ==========");
$this->customLog('info', "共处理 {$totalOrders}已完成订单");
$this->customLog('info', "共处理 {$totalOrders}{$statusName}订单");
$this->customLog('info', "新建分销订单: {$totalCreated} 条, 拨款结算: {$totalSettled} 条, 已结算跳过: {$totalSkipped} 条, 无需处理: {$totalNoAction} 个订单");
if ($statusFilter === 'paid' || $statusFilter === 'all') {
$this->customLog('info', "提示: 已支付订单拨款使用 'paid' 事件,如系统配置需订单完成后才结算,拨款可能被跳过(符合预期)");
}
// 输出新建分销订单详情
if (!empty($createdDetails)) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment