refactor(shopro): 移除重复的SplitWalletSettlement引入 移除了addons/shopro/library/regional_agent/Commission.php文件中重复的 SplitWalletSettlement类引入声明,保留唯一的引入语句以避免代码冗余。 ```
332 行
10 KiB
PHP
332 行
10 KiB
PHP
<?php
|
|
|
|
namespace addons\shopro\library\regional_agent;
|
|
|
|
use addons\shopro\model\Order as OrderModel;
|
|
use addons\shopro\model\User as UserModel;
|
|
use addons\shopro\model\regional_agent\Agent as AgentModel;
|
|
use addons\shopro\model\regional_agent\Level as LevelModel;
|
|
use addons\shopro\model\regional_agent\Order as RegionalOrderModel;
|
|
use addons\shopro\model\regional_agent\Reward as RewardModel;
|
|
use addons\shopro\library\split\SplitWalletSettlement;
|
|
|
|
/**
|
|
* 区域代理分佣
|
|
*/
|
|
class Commission
|
|
{
|
|
protected $_config;
|
|
|
|
public function __construct()
|
|
{
|
|
$this->_config = new Config();
|
|
}
|
|
|
|
/**
|
|
* 订单支付后处理区域代理分佣
|
|
*/
|
|
public function handleOrderPayed($order)
|
|
{
|
|
if (!$this->_config->isEnable()) {
|
|
return false;
|
|
}
|
|
|
|
if ($order['type'] === 'score' || empty($order['province_id'])) {
|
|
return false;
|
|
}
|
|
|
|
$order = OrderModel::with('item')->where('id', $order['id'])->find();
|
|
if (!$order || !$order['item']) {
|
|
return false;
|
|
}
|
|
|
|
$agents = $this->matchRegionalAgents($order);
|
|
if (empty($agents)) {
|
|
return false;
|
|
}
|
|
|
|
foreach ($order['item'] as $item) {
|
|
if (!$this->isGoodsRegionalEnabled($item['goods_id'])) {
|
|
continue;
|
|
}
|
|
$this->createRegionalCommissionsForItem($order, $item, $agents);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* 按收货地址匹配省/市/区县代理
|
|
*/
|
|
public function matchRegionalAgents($order)
|
|
{
|
|
$matched = [];
|
|
$areaFields = [
|
|
1 => 'province_id',
|
|
2 => 'city_id',
|
|
3 => 'area_id',
|
|
];
|
|
|
|
$levels = LevelModel::order('area_level asc')->select();
|
|
if (!$levels || count($levels) === 0) {
|
|
$levels = [
|
|
['area_level' => 1],
|
|
['area_level' => 2],
|
|
['area_level' => 3],
|
|
];
|
|
}
|
|
|
|
foreach ($levels as $levelRow) {
|
|
$areaLevel = intval($levelRow['area_level']);
|
|
$field = $areaFields[$areaLevel] ?? null;
|
|
if (!$field) {
|
|
continue;
|
|
}
|
|
$areaId = $order[$field] ?? null;
|
|
if (empty($areaId)) {
|
|
continue;
|
|
}
|
|
$agent = AgentModel::findByArea($areaId, $areaLevel);
|
|
if ($agent) {
|
|
// 校验代理绑定的用户是否存在,防止脏数据导致分佣结算崩溃
|
|
$agentUser = UserModel::get($agent['user_id']);
|
|
if (!$agentUser) {
|
|
\think\Log::error("[regional_agent] agent id={$agent['id']} user_id={$agent['user_id']} not found in fa_user, skipped");
|
|
continue;
|
|
}
|
|
$matched[] = [
|
|
'agent' => $agent,
|
|
'area_id' => $areaId,
|
|
'area_level' => $areaLevel,
|
|
];
|
|
}
|
|
}
|
|
|
|
return $matched;
|
|
}
|
|
|
|
protected function isGoodsRegionalEnabled($goodsId)
|
|
{
|
|
$row = \think\Db::name('shopro_commission_goods')->where('goods_id', $goodsId)->find();
|
|
if (!$row) {
|
|
return true;
|
|
}
|
|
return boolval($row['regional_enable'] ?? 1);
|
|
}
|
|
|
|
protected function createRegionalCommissionsForItem($order, $item, $agents)
|
|
{
|
|
$amount = floatval($item['pay_price']);
|
|
if ($amount <= 0) {
|
|
return false;
|
|
}
|
|
|
|
$mode = $this->_config->getCommissionMode();
|
|
if ($mode === 'exclusive') {
|
|
$agents = $this->filterExclusiveAgents($agents);
|
|
}
|
|
if (empty($agents)) {
|
|
return false;
|
|
}
|
|
|
|
$commissionMap = $this->calculateCommissionMap($agents, $amount, $mode);
|
|
|
|
foreach ($agents as $agentData) {
|
|
$agent = $agentData['agent'];
|
|
$commission = $commissionMap[$agent['id']] ?? 0;
|
|
if ($commission <= 0) {
|
|
continue;
|
|
}
|
|
$this->persistRegionalCommission($order, $item, $agentData, $amount, $commission);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
protected function filterExclusiveAgents($agents)
|
|
{
|
|
if (empty($agents)) {
|
|
return [];
|
|
}
|
|
usort($agents, function ($a, $b) {
|
|
return $b['area_level'] - $a['area_level'];
|
|
});
|
|
return [$agents[0]];
|
|
}
|
|
|
|
protected function calculateCommissionMap($agents, $amount, $mode)
|
|
{
|
|
$map = [];
|
|
$levelRows = [];
|
|
foreach ($agents as $agentData) {
|
|
$level = LevelModel::get($agentData['agent']['level']);
|
|
if (!$level) {
|
|
continue;
|
|
}
|
|
$effective = $this->resolveEffectiveCommission($agentData['agent'], $level);
|
|
$levelRows[] = [
|
|
'agent_id' => $agentData['agent']['id'],
|
|
'area_level' => $agentData['area_level'],
|
|
'commission' => $effective,
|
|
];
|
|
}
|
|
if (empty($levelRows)) {
|
|
return $map;
|
|
}
|
|
|
|
if ($mode === 'differential') {
|
|
return $this->calculateDifferentialMap($levelRows, $amount);
|
|
}
|
|
|
|
foreach ($levelRows as $row) {
|
|
$map[$row['agent_id']] = $this->calculateFullCommission($row['commission'], $amount);
|
|
}
|
|
return $map;
|
|
}
|
|
|
|
protected function calculateDifferentialMap($levelRows, $amount)
|
|
{
|
|
$types = [];
|
|
foreach ($levelRows as $row) {
|
|
$types[$row['commission']['commission_type']] = true;
|
|
}
|
|
if (count($types) !== 1) {
|
|
$map = [];
|
|
foreach ($levelRows as $row) {
|
|
$map[$row['agent_id']] = $this->calculateFullCommission($row['commission'], $amount);
|
|
}
|
|
return $map;
|
|
}
|
|
|
|
usort($levelRows, function ($a, $b) {
|
|
return $a['area_level'] - $b['area_level'];
|
|
});
|
|
|
|
$map = [];
|
|
$prevValue = 0;
|
|
$type = key($types);
|
|
|
|
foreach ($levelRows as $row) {
|
|
$commission = $row['commission'];
|
|
if ($type === 'rate') {
|
|
$current = floatval($commission['commission_rate']);
|
|
$effective = max(0, $current - $prevValue);
|
|
$map[$row['agent_id']] = round($amount * $effective * 0.01, 2);
|
|
$prevValue = $current;
|
|
} else {
|
|
$current = floatval($commission['commission_money']);
|
|
$effective = max(0, $current - $prevValue);
|
|
$map[$row['agent_id']] = round($effective, 2);
|
|
$prevValue = $current;
|
|
}
|
|
}
|
|
|
|
return $map;
|
|
}
|
|
|
|
/**
|
|
* 单个代理有自定义佣金时优先,否则跟随等级通用配置
|
|
*/
|
|
protected function resolveEffectiveCommission($agent, $level)
|
|
{
|
|
$type = $agent['commission_type'] ?? null;
|
|
if (!empty($type)) {
|
|
return [
|
|
'commission_type' => $type,
|
|
'commission_rate' => floatval($agent['commission_rate'] ?? 0),
|
|
'commission_money' => floatval($agent['commission_money'] ?? 0),
|
|
];
|
|
}
|
|
return [
|
|
'commission_type' => $level['commission_type'],
|
|
'commission_rate' => floatval($level['commission_rate']),
|
|
'commission_money' => floatval($level['commission_money']),
|
|
];
|
|
}
|
|
|
|
protected function calculateFullCommission($commission, $amount)
|
|
{
|
|
if ($commission['commission_type'] === 'rate') {
|
|
return round($amount * floatval($commission['commission_rate']) * 0.01, 2);
|
|
}
|
|
return round(floatval($commission['commission_money']), 2);
|
|
}
|
|
|
|
protected function persistRegionalCommission($order, $item, $agentData, $amount, $commission)
|
|
{
|
|
$agent = $agentData['agent'];
|
|
$exists = RegionalOrderModel::where('order_item_id', $item['id'])
|
|
->where('agent_id', $agent['id'])
|
|
->find();
|
|
if ($exists) {
|
|
return $exists;
|
|
}
|
|
|
|
$regionalOrder = RegionalOrderModel::create([
|
|
'order_id' => $order['id'],
|
|
'order_item_id' => $item['id'],
|
|
'buyer_id' => $order['user_id'],
|
|
'agent_id' => $agent['id'],
|
|
'agent_user_id' => $agent['user_id'],
|
|
'area_id' => $agentData['area_id'],
|
|
'area_level' => $agentData['area_level'],
|
|
'amount' => $amount,
|
|
'commission_event' => $this->_config->getCommissionEvent(),
|
|
'commission_reward_status' => 0,
|
|
]);
|
|
|
|
RewardModel::create([
|
|
'order_id' => $order['id'],
|
|
'order_item_id' => $item['id'],
|
|
'buyer_id' => $order['user_id'],
|
|
'regional_order_id' => $regionalOrder->id,
|
|
'agent_id' => $agent['id'],
|
|
'agent_user_id' => $agent['user_id'],
|
|
'type' => 'money',
|
|
'commission' => $commission,
|
|
'original_commission' => $commission,
|
|
'status' => 0,
|
|
]);
|
|
|
|
$agent->setInc('order_money', $amount);
|
|
$agent->setInc('order_count', 1);
|
|
|
|
if ($this->_config->getCommissionEvent() === 'payed') {
|
|
if (!SplitWalletSettlement::shouldDeferRegionalWallet($order, 'payed')) {
|
|
(new Reward())->settleByRegionalOrder($regionalOrder->id, 'payed');
|
|
}
|
|
}
|
|
|
|
return $regionalOrder;
|
|
}
|
|
|
|
/**
|
|
* 订单确认收货/完成时结算
|
|
*/
|
|
public function settleByEvent($event, $orderItemId)
|
|
{
|
|
$regionalOrders = RegionalOrderModel::where('order_item_id', $orderItemId)
|
|
->where('commission_reward_status', 0)
|
|
->select();
|
|
|
|
$rewardLib = new Reward();
|
|
foreach ($regionalOrders as $regionalOrder) {
|
|
if ($regionalOrder['commission_event'] === $event) {
|
|
$rewardLib->settleByRegionalOrder($regionalOrder->id, $event);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 退款退回区域代理佣金
|
|
*/
|
|
public function refundByOrderItem($orderItemId)
|
|
{
|
|
$regionalOrders = RegionalOrderModel::where('order_item_id', $orderItemId)->select();
|
|
$rewardLib = new Reward();
|
|
foreach ($regionalOrders as $regionalOrder) {
|
|
$rewardLib->backByRegionalOrder($regionalOrder->id, 'refund');
|
|
}
|
|
}
|
|
}
|