6
0
Fork 0
jiqu-library-server/app/Services/DistributionPreIncomeJobSer...

499 lines
19 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<?php
namespace App\Services;
use App\Models\AfterSale;
use App\Models\DistributionPreIncome;
use App\Models\DistributionPreIncomeJob;
use App\Models\DistributionPreIncomeLog;
use App\Models\Order;
use App\Models\OrderRefundLog;
use App\Models\UserInfo;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\DB;
class DistributionPreIncomeJobService
{
/**
* 执行分销任务
*
* @param \App\Models\DistributionPreIncomeJob $job
* @return void
*/
public function run(DistributionPreIncomeJob $job)
{
bcscale(18);
switch (get_class($job->jobable)) {
case Order::class:
$this->runOrderJob($job);
break;
case OrderRefundLog::class:
$this->runOrderRefundJob($job);
break;
case AfterSale::class:
$this->runOrderAfterSaleJob($job);
break;
}
$job->update([
'status' => DistributionPreIncomeJob::STATUS_SUCCESS,
]);
}
/**
* 处理订单售后的预收益任务
*
* @param \App\Models\DistributionPreIncomeJob $job
* @return void
*/
protected function runOrderAfterSaleJob(DistributionPreIncomeJob $job)
{
// 售后单
$afterSale = $job->jobable;
// 如果售后单不是退款或换货,则直接结束任务
if (! in_array($afterSale->type, [
AfterSale::TYPE_REFUND,
AfterSale::TYPE_REFUND_AND_RETURN,
AfterSale::TYPE_CHANGE,
])) {
return;
}
// 售后商品
$afterSaleProduct = $afterSale->orderProduct;
// 如果售后商品是赠品,则直接结束任务
if ($afterSaleProduct->isGift()) {
return;
}
$preIncomes = DistributionPreIncome::where('order_id', $afterSale->order_id)->get();
$time = now();
$preIncomeLogs = [];
foreach ($preIncomes as $preIncome) {
$rule = $preIncome->rule;
if ($preIncome->type === DistributionPreIncome::TYPE_PRICE_DIFF) {
// 售后商品的总差价(元)
$totalDiffPrice = 0;
if (! is_null($afterSaleProduct->vip_price) && $afterSaleProduct->vip_discount_amount === 0) {
$diffPrice = $afterSaleProduct->sell_price - $afterSaleProduct->vip_price;
if ($diffPrice > 0) {
$totalDiffPrice = bcdiv($diffPrice * $afterSaleProduct->quantity, '100');
}
}
if (bccomp($totalDiffPrice, '0', 2) <= 0) {
continue;
}
$changeAmount = 0;
if ($afterSaleProduct->total_amount > 0) {
$amount = $afterSale->amount;
if ($amount >= $afterSaleProduct->total_amount) {
$amount = $afterSaleProduct->total_amount;
}
$changeAmount = bcdiv(bcmul($totalDiffPrice, $amount), $afterSaleProduct->total_amount);
} else {
$qty = $afterSale->num;
if ($qty > $afterSaleProduct->quantity) {
$qty = $afterSaleProduct->quantity;
}
$changeAmount = bcdiv(bcmul($totalDiffPrice, $qty), $afterSaleProduct->quantity);
}
// 差价奖励按变更的差价计算
$changeRevenue = bcmul($changeAmount, $rule['bonus_rate']);
$changeRevenue = bcmul($changeRevenue, bcsub('1', $rule['fee_rate']));
$changeRevenue = round($changeRevenue, 2);
// 变更金额
$changeAmount = round($changeAmount, 2);
// 变更成长值
$changeSalesValue = $afterSale->sales_value;
$preIncome->update([
'total_amount' => DB::raw("total_amount-{$changeAmount}"),
'total_revenue' => DB::raw("total_revenue-{$changeRevenue}"),
'total_sales_value' => DB::raw("total_sales_value-{$changeSalesValue}"),
]);
$preIncomeLogs[] = [
'pre_income_id' => $preIncome->id,
'pre_income_job_id' => $job->id,
'change_amount' => bcmul($changeAmount, '-1'),
'change_revenue' => bcmul($changeRevenue, '-1'),
'change_sales_value' => bcmul($changeSalesValue, '-1'),
'remarks' => $afterSale->isChange() ? '订单换货' : '订单退款',
'created_at' => $time,
'updated_at' => $time,
];
} elseif (in_array($preIncome->type, [DistributionPreIncome::TYPE_LEVEL_DIFF, DistributionPreIncome::TYPE_LEVEL_SAME])) {
if (bccomp($afterSale->sales_value, '0', 2) <= 0) {
continue;
}
$changeAmount = $afterSale->amount;
if ($changeAmount > $afterSaleProduct->total_amount) {
$changeAmount = $afterSaleProduct->total_amount;
}
$changeAmount = bcdiv($changeAmount, '100');
$changeSalesValue = $afterSale->sales_value;
// 级差奖励和平级奖励按变更的销售值算收益
$changeRevenue = bcmul($changeSalesValue, $rule['bonus_rate']);
$changeRevenue = bcmul($changeRevenue, bcsub('1', $rule['fee_rate']));
$changeRevenue = round($changeRevenue, 2);
$preIncome->update([
'total_amount' => DB::raw("total_amount-{$changeAmount}"),
'total_revenue' => DB::raw("total_revenue-{$changeRevenue}"),
'total_sales_value' => DB::raw("total_sales_value-{$changeSalesValue}"),
]);
$preIncomeLogs[] = [
'pre_income_id' => $preIncome->id,
'pre_income_job_id' => $job->id,
'change_amount' => bcmul($changeAmount, '-1'),
'change_revenue' => bcmul($changeRevenue, '-1'),
'change_sales_value' => bcmul($changeSalesValue, '-1'),
'remarks' => $afterSale->isChange() ? '订单换货' : '订单退款',
'created_at' => $time,
'updated_at' => $time,
];
}
}
DistributionPreIncomeLog::insert($preIncomeLogs);
}
/**
* 处理取消订单的预收益任务
*
* @param \App\Models\DistributionPreIncomeJob $job
* @return void
*/
protected function runOrderRefundJob(DistributionPreIncomeJob $job)
{
$time = now();
$preIncomeLogs = [];
$orderRefundLog = $job->jobable;
$preIncomes = DistributionPreIncome::where('order_id', $orderRefundLog->order_id)->get();
foreach ($preIncomes as $preIncome) {
$original = $preIncome->replicate();
$preIncome->update([
'total_amount' => 0,
'total_sales_value' => 0,
'total_revenue' => 0,
'status' => DistributionPreIncome::STATUS_PROCESSED,
]);
$preIncomeLogs[] = [
'pre_income_id' => $preIncome->id,
'pre_income_job_id' => $job->id,
'change_amount' => bcmul($original->total_amount, '-1'),
'change_sales_value' => bcmul($original->total_sales_value, '-1'),
'change_revenue' => bcmul($original->total_revenue, '-1'),
'remarks' => '取消订单',
'created_at' => $time,
'updated_at' => $time,
];
}
DistributionPreIncomeLog::insert($preIncomeLogs);
}
/**
* 处理下单预的预收益任务
*
* @param \App\Models\DistributionPreIncomeJob $job
* @return void
*/
protected function runOrderJob(DistributionPreIncomeJob $job)
{
// 订单信息
$order = $job->jobable;
// 下单用户信息
$user = $order->user->userInfo;
// 总销售值
$totalSalesValue = $order->sales_value;
// 总差价
$totalDiffPrice = 0;
if ($order->vip_discount_amount === 0) {
foreach ($order->products as $product) {
// 赠品不算成长值和差价
if ($product->isGift()) {
continue;
}
// 如果订单商品有会员价,并且没有会员折扣时,才计算总差价
if (! is_null($product->vip_price) && $product->vip_discount_amount === 0) {
$diffPrice = $product->sell_price - $product->vip_price;
if ($diffPrice > 0) {
$totalDiffPrice = bcadd($totalDiffPrice, bcmul(bcdiv($diffPrice, '100'), $product->quantity));
}
}
}
}
// 分销配置
$config = $this->getConfig();
$preIncomeLogs = [];
// 推粉丝赚差价
// 1. 总差价必须大于0
// 2. 下单用户必须有邀请人
// 3. 下单用户的邀请人必须可以享受分红
if (
$totalDiffPrice > 0
&& $user->inviter_id
&& $user->inviterInfo->bonusable
) {
// 手续费率
$feeRate = $config['price_diff_fee_rate'] ?? '0';
// 奖励比例
$bonusRate = '1';
// 总收益
$totalRevenue = bcmul($totalDiffPrice, $bonusRate);
// 扣除手续费
$totalRevenue = bcmul($totalRevenue, bcsub('1', $feeRate));
$preIncome = $user->inviterInfo->distributionPreIncomes()->create([
'order_id' => $order->id,
'type' => DistributionPreIncome::TYPE_PRICE_DIFF,
'agent_level' => $user->inviterInfo->agent_level,
'total_amount' => $totalDiffPrice,
'total_sales_value' => $totalSalesValue,
'total_revenue' => round($totalRevenue, 2),
'rule' => [
'fee_rate' => bcmul($feeRate, '1', 2),
'bonus_rate' => bcmul($bonusRate, '1', 2),
],
'remarks' => "订单号: {$order->sn}",
]);
$preIncomeLogs[] = [
'pre_income_id' => $preIncome->id,
'pre_income_job_id' => $job->id,
'change_amount' => bcdiv($totalDiffPrice, 100),
'change_sales_value' => $preIncome->total_sales_value,
'change_revenue' => $preIncome->total_revenue,
'remarks' => "订单号: {$order->sn}",
'created_at' => $preIncome->created_at,
'updated_at' => $preIncome->created_at,
];
}
// 如果总销售值大于0需计算各级代理的奖励
if ($totalSalesValue > 0) {
// 可获取奖励
$agents = $this->getAgentsByUser($user);
$lastAgent = null;
// 已分配的级差奖励比例
$assignedLvlDiffBonusRate = 0;
foreach ($agents as $agent) {
$rule = Arr::get($config, "rules.{$agent->agent_level_key}");
if ($lastAgent && $agent->agent_level === $lastAgent->agent_level) {
/*
|-----------------------------------------------
| 平级奖励
|-----------------------------------------------
*/
if ($agent->bonusable) {
$bonusRate = $rule['lvl_same_bonus_rate'] ?? '0';
if (bccomp($bonusRate, '0') === 1) {
// 手续费率
$feeRate = $config['lvl_same_bonus_fee_rate'] ?? '0';
// 总收益
$totalRevenue = bcmul($totalSalesValue, $bonusRate);
// 扣除手续费
$totalRevenue = bcmul($totalRevenue, bcsub('1', $feeRate));
$preIncome = $agent->distributionPreIncomes()->create([
'order_id' => $order->id,
'type' => DistributionPreIncome::TYPE_LEVEL_SAME,
'agent_level' => $agent->agent_level,
'total_amount' => $this->calculateOrderTotalAmount($order),
'total_sales_value' => $totalSalesValue,
'total_revenue' => round($totalRevenue, 2),
'rule' => [
// 手续费率
'fee_rate' => bcmul($feeRate, '1', 2),
// 实际奖励比例
'bonus_rate' => bcmul($bonusRate, '1', 2),
],
'remarks' => "订单号: {$order->sn}",
]);
$preIncomeLogs[] = [
'pre_income_id' => $preIncome->id,
'pre_income_job_id' => $job->id,
'change_amount' => $preIncome->total_amount,
'change_sales_value' => $preIncome->total_sales_value,
'change_revenue' => $preIncome->total_revenue,
'remarks' => "订单号: {$order->sn}",
'created_at' => $preIncome->created_at,
'updated_at' => $preIncome->created_at,
];
}
}
} else {
/*
|-----------------------------------------------
| 级差奖励
|-----------------------------------------------
*/
$lvlDiffBonusRate = $rule['lvl_diff_bonus_rate'] ?? '0';
if (bccomp($lvlDiffBonusRate, '0') === 1) {
// 可得级差奖励比例 = 当前等级的级差奖励 - 已分配的级差奖励比例
$bonusRate = bcsub($lvlDiffBonusRate, $assignedLvlDiffBonusRate);
// 如果可得级差奖励比例小于或等于0则停止分润
if (bccomp($bonusRate, '0') <= 0) {
break;
}
if ($agent->bonusable) {
// 手续费率
$feeRate = $config['lvl_diff_bonus_fee_rate'] ?? '0';
// 总收益
$totalRevenue = bcmul($totalSalesValue, $bonusRate);
// 扣除手续费
$totalRevenue = bcmul($totalRevenue, bcsub('1', $feeRate));
$preIncome = $agent->distributionPreIncomes()->create([
'order_id' => $order->id,
'type' => DistributionPreIncome::TYPE_LEVEL_DIFF,
'agent_level' => $agent->agent_level,
'total_amount' => $this->calculateOrderTotalAmount($order),
'total_sales_value' => $totalSalesValue,
'total_revenue' => round($totalRevenue, 2),
'rule' => [
// 手续费率
'fee_rate' => bcmul($feeRate, '1', 2),
// 实际奖励比例
'bonus_rate' => bcmul($bonusRate, '1', 2),
// 级差奖励比例
'lvl_diff_bonus_rate' => bcmul($lvlDiffBonusRate, '1', 2),
],
'remarks' => "订单号: {$order->sn}",
]);
$preIncomeLogs[] = [
'pre_income_id' => $preIncome->id,
'pre_income_job_id' => $job->id,
'change_amount' => $preIncome->total_amount,
'change_sales_value' => $preIncome->total_sales_value,
'change_revenue' => $preIncome->total_revenue,
'remarks' => "订单号: {$order->sn}",
'created_at' => $preIncome->created_at,
'updated_at' => $preIncome->created_at,
];
}
$assignedLvlDiffBonusRate = $lvlDiffBonusRate;
}
}
$lastAgent = $agent;
}
}
DistributionPreIncomeLog::insert($preIncomeLogs);
}
/**
* 根据下单用户,获取参与结算的所有代理
*
* @param \App\Models\UserInfo $user
* @return array
*/
protected function getAgentsByUser(UserInfo $user): array
{
// 可参与分销的所有代理
// 代理的等级必须从低到过且同一等级连续出现次数不超过2次
$agents = [
$user,
];
// 如果下单用户没有上级,则只有下单用户参与奖励计算
if (empty($pids = $user->parent_ids)) {
return $agents;
}
// 下单用户的所有上级
$ancestors = UserInfo::whereIn('user_id', $pids)->latest('depth')->get();
// 最后加入分销链的代理
$last = $user;
// 最后加入分销链的代理的前一个代理
$previous = null;
foreach ($ancestors as $ancestor) {
if ($previous && $previous->agent_level_rank >= $ancestor->agent_level_rank) {
continue;
}
if ($ancestor->agent_level_rank >= $last->agent_level_rank) {
$previous = $last;
$last = $ancestor;
$agents[] = $last;
}
}
return $agents;
}
/**
* 订单总金额
*
* @param \App\Models\Order $order
* @return float
*/
protected function calculateOrderTotalAmount(Order $order)
{
$totalAmount = bcadd($order->products_total_amount, $order->shipping_fee);
$totalAmount = bcsub($totalAmount, $order->coupon_discount_amount);
$totalAmount = bcsub($totalAmount, $order->vip_discount_amount);
$totalAmount = bcsub($totalAmount, $order->reduced_amount);
return round(bcdiv($totalAmount, 100), 2);
}
/**
* 分销配置
*
* @return array
*/
protected function getConfig(): array
{
return app_settings('distribution');
}
}