文件
xionggeshop/addons/shopro/library/split/SplitCalculator.php
2026-09-29 11:52:53 +08:00

217 行
7.3 KiB
PHP

<?php
namespace addons\shopro\library\split;
use addons\shopro\model\Order;
use addons\shopro\model\split\Receiver;
use addons\shopro\model\split\Rule;
use addons\shopro\model\commission\Reward as CommissionReward;
use addons\shopro\model\regional_agent\Reward as RegionalReward;
use addons\shopro\model\UserOauth;
class SplitCalculator
{
protected $config;
public function __construct()
{
$this->config = new Config();
}
/**
* 计算订单分账明细
* @return array [['role_type','role_id','receiver_id','receiver_account','receiver_type','receiver_name','amount','description']]
*/
public function calculate($orderId)
{
$order = Order::get($orderId);
if (!$order || !in_array($order['pay_type'], ['wechat', 'huifu_wechat'])) {
return [];
}
$payFee = floatval($order['pay_fee']);
if ($payFee <= 0) {
return [];
}
$source = $this->config->getAmountSource();
$items = [];
if (in_array($source, ['commission', 'mixed'])) {
$items = $this->calculateFromCommission($orderId);
}
if (empty($items) && in_array($source, ['rule', 'mixed'])) {
$items = $this->calculateFromRules($payFee);
}
$allocated = array_sum(array_column($items, 'amount'));
$maxSplit = $payFee * $this->config->getMaxRate() / 100;
if ($allocated > $maxSplit && $allocated > 0) {
$ratio = $maxSplit / $allocated;
foreach ($items as &$item) {
$item['amount'] = round($item['amount'] * $ratio, 2);
}
unset($item);
}
return $items;
}
protected function getRegionalRewardsByOrderId($orderId)
{
try {
return RegionalReward::where('order_id', $orderId)->where('status', '>=', 0)->select();
} catch (\Exception $e) {
return RegionalReward::alias('rr')
->join('shopro_regional_agent_order ro', 'ro.id = rr.regional_order_id')
->where('ro.order_id', $orderId)
->where('rr.status', '>=', 0)
->field('rr.*')
->select();
}
}
protected function calculateFromCommission($orderId)
{
$items = [];
$commissionRewards = CommissionReward::where('order_id', $orderId)->where('status', '>=', 0)->select();
foreach ($commissionRewards as $reward) {
$agent = \addons\shopro\model\commission\Agent::get($reward['agent_id']);
$userId = $agent ? $agent['user_id'] : 0;
if (!$userId) {
continue;
}
$receiver = $this->getReceiver('promoter', $userId);
if (!$receiver) {
continue;
}
$amount = floatval($reward['commission']);
if ($amount <= 0) {
continue;
}
$items[] = $this->buildItem('promoter', $userId, $receiver, $amount, '推广员差价');
}
$regionalRewards = $this->getRegionalRewardsByOrderId($orderId);
foreach ($regionalRewards as $reward) {
$receiver = $this->getReceiver('regional_agent', $reward['agent_user_id']);
if (!$receiver) {
continue;
}
$amount = floatval($reward['commission']);
if ($amount <= 0) {
continue;
}
$items[] = $this->buildItem('regional_agent', $reward['agent_user_id'], $receiver, $amount, '区域公司差价');
}
return $items;
}
protected function calculateFromRules($payFee)
{
$items = [];
$rules = Rule::where('status', 'normal')->order('priority desc')->select();
foreach ($rules as $rule) {
if (in_array($rule['role_type'], ['platform'])) {
continue;
}
$receiver = $this->getReceiver($rule['role_type'], 0, true);
if (!$receiver) {
continue;
}
if ($rule['rule_type'] === 'rate') {
$amount = round($payFee * floatval($rule['rule_value']) / 100, 2);
} else {
$amount = round(floatval($rule['rule_value']), 2);
}
if ($amount <= 0) {
continue;
}
$items[] = $this->buildItem($rule['role_type'], 0, $receiver, $amount, '规则分账');
}
return $items;
}
protected function buildItem($roleType, $roleId, $receiver, $amount, $desc)
{
return [
'role_type' => $roleType,
'role_id' => $roleId,
'receiver_id' => $receiver['id'] ?? 0,
'receiver_account' => $receiver['receiver_account'],
'receiver_type' => $receiver['receiver_type'],
'receiver_name' => $receiver['receiver_name'] ?? '',
'amount' => round($amount, 2),
'description' => $desc,
];
}
protected function getReceiver($roleType, $roleId, $ruleMode = false)
{
$channel = $this->config->isHuifuMode() ? 'huifu' : 'wechat';
$query = Receiver::where('role_type', $roleType)->where('status', 'normal');
if ($roleId) {
$query->where('role_id', $roleId);
}
$receiver = $query->where(function ($q) use ($channel) {
$q->where('channel', $channel)->whereOr('channel', null)->whereOr('channel', '');
})->find();
if ($receiver) {
return $receiver;
}
if ($this->config->isHuifuMode()) {
if ($roleType === 'platform') {
$account = $this->config->getPlatformHuifuId();
if ($account) {
return [
'id' => 0,
'receiver_account' => $account,
'receiver_type' => 'HUIFU_ID',
'receiver_name' => $this->config->getPlatformReceiverName(),
];
}
}
return null;
}
if (!$ruleMode && in_array($roleType, ['promoter', 'regional_agent'])) {
$oauth = UserOauth::where('user_id', $roleId)->where('provider', 'Wechat')->where('platform', 'wxMiniProgram')->find();
if ($oauth && $oauth['openid']) {
return Receiver::create([
'role_type' => $roleType,
'role_id' => $roleId,
'channel' => 'wechat',
'receiver_type' => 'PERSONAL_OPENID',
'receiver_account' => $oauth['openid'],
'receiver_name' => '用户' . $roleId,
'relation_type' => 'USER',
'wx_status' => 0,
'status' => 'normal',
'createtime' => time(),
'updatetime' => time(),
]);
}
}
if ($roleType === 'platform') {
$account = $this->config->getPlatformReceiverAccount();
if ($account) {
return [
'id' => 0,
'receiver_account' => $account,
'receiver_type' => 'MERCHANT_ID',
'receiver_name' => $this->config->getPlatformReceiverName(),
];
}
}
return null;
}
}