6
0
Fork 0

处理付款订单

release
李静 2022-01-18 16:27:32 +08:00
parent f22a9a7cc5
commit 0b845f4efc
2 changed files with 384 additions and 19 deletions

View File

@ -2,10 +2,12 @@
namespace App\Console\Commands\Dealer;
use App\Enums\DealerEarningStatus;
use App\Enums\DealerLvl;
use App\Enums\DealerOrderSettleState;
use App\Enums\DealerOrderStatus;
use App\Models\Dealer;
use App\Models\DealerChannelSubsidyLog;
use App\Models\DealerManagerSalesLog;
use App\Models\DealerManageSubsidyLog;
use App\Models\DealerOrder;
@ -47,7 +49,7 @@ class OrderProcessCommand extends Command
DealerOrderStatus::Completed,
])->chunkById(200, function ($orders) {
$orders->load([
'userInfo.dealer',
'dealer.userInfo',
'products.productManageSubsidyRules',
]);
@ -77,27 +79,236 @@ class OrderProcessCommand extends Command
*/
protected function handleDealerOrder(DealerOrder $dealerOrder)
{
$tz = now();
// 获取下单经销商的所有上级经销商
$dealers = $this->getDealers($dealerOrder->userInfo);
$tz = now()->toDateTimeString();
// 当前链上的全部经销商(含下单经销商)
$chainDealers = [$dealerOrder->userInfo->dealer, ...$dealers];
$dealers = [
$dealerOrder->dealer,
...$dealerOrder->dealer->getDealers(),
];
// 签约经销商的进货日志
$this->handlePurchaseLogsOfContractedDealer($dealerOrder, $tz);
// 管理者的销售业绩
$this->handleManagerSalesLogs($dealerOrder, $chainDealers, $tz);
$this->handleManagerSalesLogs($dealerOrder, $dealers, $tz);
// 一级签约经销商和二级经销商的管理津贴
$this->handleManageSubsidyLogs($dealerOrder, $chainDealers, $tz);
$this->handleManageSubsidyLogs($dealerOrder, $dealers, $tz);
// 渠道补贴
$this->handleChannelSubsidy($dealerOrder);
if ($dealerOrder->dealer->wasChanged('lvl')) {
foreach ($dealers as $dealer) {
$dealer->attemptUpgrade();
}
}
// 将订单标记为已处理
// $dealerOrder->forceFill([
// 'settle_state' => DealerOrderSettleState::Processed,
// ])->save();
$dealerOrder->forceFill([
'settle_state' => DealerOrderSettleState::Processed,
])->save();
}
/**
* 计算渠道补贴
*
* @param \App\Models\DealerOrder $dealerOrder
* @return void
*/
protected function handleChannelSubsidy(DealerOrder $dealerOrder)
{
$lvl = $dealerOrder->dealer->lvl;
if ($dealerOrder->total_amount >= app_settings('dealer.upgrade_amount_'.DealerLvl::Contracted->value)) {
// 升级为签约
if ($lvl->value < DealerLvl::Contracted->value) {
$lvl = DealerLvl::Contracted;
}
} elseif ($dealerOrder->total_amount >= app_settings('dealer.upgrade_amount_'.DealerLvl::Special->value)) {
// 升级为特约
if ($lvl->value < DealerLvl::Special->value) {
$lvl = DealerLvl::Special;
}
} elseif ($dealerOrder->total_amount >= app_settings('dealer.upgrade_amount_'.DealerLvl::Gold->value)) {
// 升级为金牌
if ($lvl->value < DealerLvl::Gold->value) {
$lvl = DealerLvl::Gold;
}
}
// 如果经销商等级小于金牌,则没有渠道补贴
if ($lvl->value < DealerLvl::Gold->value) {
return;
}
[$dealers, $rule] = $this->mapDealersAndRuleOfChannel($dealerOrder->dealer, $lvl);
// 升级金额
$upgradeAmount = app_settings('dealer.upgrade_amount_'.$lvl->value);
// 手续费比例
$feeRate = bcdiv(app_settings('dealer.fee_rate'), '100', 10);
foreach ($dealers as $key => $dealer) {
$ruleKey = $dealer->lvl->value.'_'.$key;
if ($dealer->lvl->value >= DealerLvl::Contracted->value) {
$ruleKey = DealerLvl::Contracted->value.'_'.$key;
}
// 补贴金额
$subsidyAmount = $rule[$ruleKey];
$totalAmount = bcmul($subsidyAmount, $dealerOrder->total_amount, 10);
$totalAmount = bcdiv($totalAmount, $upgradeAmount, 3);
$totalAmount = round($totalAmount, 2);
$channelSubsidyLog = DealerChannelSubsidyLog::create([
'user_id' => $dealer->user_id,
'lvl' => $dealer->lvl,
'order_id' => $dealerOrder->id,
'total_amount' => $totalAmount,
'order_id' => $dealerOrder->id,
'remark' => "补贴总额={$dealerOrder->total_amount}/{$upgradeAmount}*{$subsidyAmount}",
]);
$fee = bcmul($totalAmount, bcdiv($feeRate, '100', 5), 3);
$fee = round($fee, 2);
$channelSubsidyLog->earning()->create([
'user_id' => $dealer->user_id,
'lvl' => $dealer->lvl,
'is_manager' => $dealer->is_manager,
'total_amount' => $totalAmount,
'total_earnings' => bcsub($totalAmount, $fee, 2),
'fee' => $fee,
'fee_rate' => $feeRate,
'payer_id' => $dealerOrder->consignor_id,
'status' => DealerEarningStatus::Pending,
'remark' => "订单号: {$dealerOrder->sn}",
]);
}
$dealerOrder->dealer->upgrade($lvl, '进货升级');
}
/**
* 获取渠道补贴经销商和补贴规则
*
* @param \App\Models\Dealer $dealer
* @param \App\Enums\DealerLvl $lvl
* @return array
*/
protected function mapDealersAndRuleOfChannel(Dealer $dealer, DealerLvl $lvl): array
{
// 渠道补贴经销商
$dealers = [];
// 渠道补贴规则
$rule = null;
// 是否升级
$isUp = $lvl->value > $dealer->lvl->value;
// 最后参与渠道补贴的经销商
$last = null;
foreach ($dealer->getRealDealers() as $_dealer) {
// 如果经销商等级小于金牌, 那么跳过
if ($_dealer->lvl->value < DealerLvl::Gold->value) {
continue;
}
if ($lvl->value >= DealerLvl::Contracted->value) {
if ($last === null) {
if ($_dealer->lvl->value >= DealerLvl::Contracted->value) {
// 渠道补贴规则: 签约 -> 签约 -> 签约
$rule = app_settings(sprintf(
'dealer.channel_rules.%s_%s',
DealerLvl::Contracted->value,
DealerLvl::Contracted->value
));
$dealers[] = $_dealer;
$last = $_dealer;
} elseif ($isUp && $_dealer->isSpecialDealer()) {
// 渠道补贴规则: 签约 -> 特邀 -> 签约 -> 签约
$rule = app_settings(sprintf(
'dealer.channel_rules.%s_%s',
DealerLvl::Contracted->value,
DealerLvl::Special->value
));
$dealers[] = $_dealer;
$last = $_dealer;
}
} elseif ($_dealer->lvl->value >= DealerLvl::Contracted->value) {
$dealers[] = $_dealer;
// 如果最后参与渠道补贴的经销商是签约, 那么已经找到所有参与渠道补贴的经销商
if ($last->lvl->value >= DealerLvl::Contracted->value) {
break;
}
$last = $_dealer;
}
} elseif ($lvl === DealerLvl::Special) {
if ($_dealer->lvl->value > DealerLvl::Special->value) {
break;
}
if ($last === null) {
if ($_dealer->isSpecialDealer()) {
// 渠道补贴规则: 特邀 -> 特邀 -> 特邀
$rule = app_settings(sprintf(
'dealer.channel_rules.%s_%s',
DealerLvl::Special->value,
DealerLvl::Special->value
));
$dealers[] = $_dealer;
$last = $_dealer;
} elseif ($isUp && $_dealer->isGoldDealer()) {
// 渠道补贴规则: 特邀 -> 金牌 -> 特邀 -> 特邀
$rule = app_settings(sprintf(
'dealer.channel_rules.%s_%s',
DealerLvl::Special->value,
DealerLvl::Gold->value
));
$dealers[] = $_dealer;
$last = $_dealer;
}
} elseif ($_dealer->isSpecialDealer()) {
$dealers[] = $_dealer;
if ($last->isSpecialDealer()) {
break;
}
$last = $_dealer;
}
} elseif ($lvl === DealerLvl::Gold) {
if ($_dealer->lvl->value >= DealerLvl::Gold->value) {
if ($_dealer->isGoldDealer()) {
// 渠道补贴规则: 金牌 -> 金牌
$rule = app_settings(sprintf(
'dealer.channel_rules.%s_%s',
DealerLvl::Gold->value,
DealerLvl::Gold->value
));
$dealers[] = $_dealer;
}
break;
}
}
}
return [$dealers, $rule];
}
/**
@ -117,7 +328,7 @@ class OrderProcessCommand extends Command
if ($dealer->lvl->value < DealerLvl::Contracted->value) {
// 如果订单金额小于升级签约经销商的金额,则结束
if ($dealerOrder->total_amount < 26400) {
if ($dealerOrder->total_amount < app_settings('dealer.upgrade_amount_'.DealerLvl::Contracted->value)) {
return;
}
@ -271,23 +482,23 @@ class OrderProcessCommand extends Command
}
/**
* 获取给定用户的上级经销商
* 获取给定用户的实际上级经销商
*
* @param \App\Models\UserInfo $userInfo
* @return array
*/
protected function getDealers(UserInfo $userInfo): array
protected function getRealDealers(UserInfo $userInfo): array
{
$ancestors = [];
if (empty($pids = $userInfo->parent_ids)) {
if (empty($pids = $userInfo->real_parent_ids)) {
return $ancestors;
}
$ancestors = UserInfo::with(['dealer'])
->whereIn('user_id', $pids)
->latest('depth')
->get(['user_id', 'depth']);
->get(['user_id']);
return $ancestors->map(function ($item) {
return $item->dealer;

View File

@ -139,15 +139,169 @@ class Dealer extends Model
}
/**
* 变更等级
* 获取直属金牌经销商数量
*
* @return int
*/
public function getDirectGoldDealersCount(): int
{
return static::whereHas('userInfo', function ($query) {
$query->where('inviter_id', $this->user_id);
})->where('lvl', '>=', DealerLvl::Gold)->count();
}
/**
* 获取直属的特邀经销商数量
*
* @return int
*/
public function getDirectSpecialDealersCount(): int
{
return static::whereHas('userInfo', function ($query) {
$query->where('inviter_id', $this->user_id);
})->where('lvl', '>=', DealerLvl::Special)->count();
}
/**
* 获取直属的签约经销商数量
*
* @return int
*/
public function getDirectContractedDealersCount(): int
{
return static::whereHas('userInfo', function ($query) {
$query->where('inviter_id', $this->user_id);
})->where('lvl', '>=', DealerLvl::Contracted)->count();
}
/**
* 获取不同线上的非直属签约经销商人数(每条线上最多算一个)
*
* @return int
*/
public function getIndirectContractedDealersCount(): int
{
$path = $this->userInfo->full_path;
$dealers = static::whereHas('userInfo', function ($query) use ($path) {
$query->where('inviter_id', '!=', $this->user_id)->where('path', 'like', "{$path}%");
})->where('lvl', '>=', DealerLvl::Contracted)->get();
$dealers->load('userInfo:user_id,path');
$lines = [];
foreach ($dealers as $dealer) {
preg_match("#\A{$path}\d+/#", $dealer->full_path, $matches);
$line = $matches[0];
if (! isset($lines[$line])) {
$lines[$line] = 1;
}
}
return count($lines);
}
/**
* 获取直属的二级经销商数量
*
* @return int
*/
public function getDirectSecondaryDealersCount(): int
{
return static::whereHas('userInfo', function ($query) {
$query->where('inviter_id', $this->user_id);
})->where('lvl', '>=', DealerLvl::Special)->count();
}
/**
* 尝试升级
*
* @return void
*/
public function attemptUpgrade()
{
$lvl = $this->lvl;
if (in_array($lvl, [DealerLvl::None, DealerLvl::Top])) {
return;
}
$remark = '';
if ($lvl === DealerLvl::Gold && $this->getDirectGoldDealersCount() >=5) {
$lvl = DealerLvl::Special;
$remark .= '有5个直推金牌';
}
if ($lvl === DealerLvl::Special && $this->getDirectSpecialDealersCount() >= 4) {
$lvl = DealerLvl::Contracted;
if ($remark !== '') {
$remark .= ';';
}
$remark .= '有4个直推特邀';
}
if ($lvl === DealerLvl::Contracted) {
// 直推签约经销商数量
$directDealersCount = $this->getDirectContractedDealersCount();
if ($directDealersCount >= 3) {
$surplus = 9 - $directDealersCount;
if ($surplus <= 0) {
$lvl = DealerLvl::Secondary;
if ($remark !== '') {
$remark .= ';';
}
$remark .= "{$directDealersCount}个直推签约";
} else {
// 非直属签约人数
$indirectDealersCount = $this->getIndirectContractedDealersCount();
if ($indirectDealersCount >= $surplus) {
$lvl = DealerLvl::Secondary;
if ($remark !== '') {
$remark .= ';';
}
$remark .= "{$directDealersCount}个直推签约,{$indirectDealersCount}个间接签约";
}
}
}
}
if ($lvl === DealerLvl::Secondary && $this->getDirectSecondaryDealersCount() >= 4) {
$lvl = DealerLvl::Top;
if ($remark !== '') {
$remark .= ';';
}
$remark .= '有4个直推二级';
}
$this->upgrade($lvl, $remark);
}
/**
* 直接升级
*
* @param \App\Enums\DealerLvl $lvl
* @param string|null $remark
* @return void
*/
public function changeLvl(DealerLvl $lvl, ?string $remark = null)
public function upgrade(DealerLvl $lvl, ?string $remark = null)
{
if ($this->lvl === $lvl) {
if ($this->lvl->value >= $lvl->value) {
return;
}