285 lines
9.2 KiB
PHP
285 lines
9.2 KiB
PHP
<?php
|
|
|
|
namespace App\Console\Commands\Dealer;
|
|
|
|
use App\Enums\DealerEarningStatus;
|
|
use App\Enums\DealerLvl;
|
|
use App\Enums\DealerManageSubsidyStatus;
|
|
use App\Enums\DealerOrderSettleState;
|
|
use App\Models\Dealer;
|
|
use App\Models\DealerManageSubsidy;
|
|
use App\Models\DealerManageSubsidyLog;
|
|
use App\Models\DealerOrder;
|
|
use Illuminate\Console\Command;
|
|
use Illuminate\Support\Carbon;
|
|
use Illuminate\Support\Facades\DB;
|
|
|
|
class ManageSubsidySettleCommand extends Command
|
|
{
|
|
/**
|
|
* The name and signature of the console command.
|
|
*
|
|
* @var string
|
|
*/
|
|
protected $signature = 'dealer:manage-subsidy-settle';
|
|
|
|
/**
|
|
* The console command description.
|
|
*
|
|
* @var string
|
|
*/
|
|
protected $description = '结算一级经销商和二级经销商的管理津贴';
|
|
|
|
/**
|
|
* Execute the console command.
|
|
*
|
|
* @return int
|
|
*/
|
|
public function handle()
|
|
{
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| 管理津贴结算
|
|
|--------------------------------------------------------------------------
|
|
|
|
|
| 管理津贴结算时间为每月的5号和20号。
|
|
|
|
|
| 5号结算上月20号0点0分0秒到当月4号23点59分59秒的管理津贴
|
|
| 20号结算当月5号0点0分0秒到19号23点59分59秒的管理津贴
|
|
|
|
|
*/
|
|
|
|
$tz = now();
|
|
|
|
if ($tz->day >= 20) {
|
|
// 结算当月5号-19号的管理津贴
|
|
$startAt = $tz->copy()->setDay(5)->startOfDay();
|
|
$endAt = $tz->copy()->setDay(19)->endOfDay();
|
|
} elseif ($tz->day >= 5) {
|
|
// 结算上月20号-到当月4号的管理津贴
|
|
$startAt = $tz->copy()->subMonthNoOverflow()->set('day', 20)->startOfDay();
|
|
$endAt = $tz->copy()->set('day', 4)->endOfDay();
|
|
} else {
|
|
// 结算上月5号-到19号的管理津贴
|
|
$startAt = $tz->copy()->subMonthNoOverflow()->setDay(5)->startOfDay();
|
|
$endAt = $tz->copy()->subMonthNoOverflow()->setDay(19)->endOfDay();
|
|
}
|
|
|
|
$head = '【'.$startAt->format('Y/m/d').'-'.$endAt->format('Y/m/d').'】';
|
|
|
|
$ordersCount = DealerOrder::onlyCompleted()
|
|
->where('settle_state', '!=', DealerOrderSettleState::Completed)
|
|
->whereNotNull('shippinged_time')
|
|
->where('shippinged_time', '<=', $endAt)
|
|
->count();
|
|
|
|
if ($ordersCount > 0) {
|
|
return $this->warn("{$head} 订单还没有结算完成!");
|
|
}
|
|
|
|
$this->info("{$head}------------[开始]管理津贴结算------------".PHP_EOL);
|
|
|
|
$this->info("{$head}管理津贴初始化...");
|
|
$this->initializeManageSubsidies($startAt, $endAt, 500);
|
|
$this->info("{$head}管理津贴初始化完成".PHP_EOL);
|
|
|
|
$this->info("{$head}管理津贴结算...");
|
|
$this->settleManageSubsidies($startAt, $endAt);
|
|
$this->info("{$head}管理津贴结算完成".PHP_EOL);
|
|
|
|
$this->info("{$head}Done! 总耗时: ".$this->formatDuration($tz->diffInMilliseconds(now(), false)));
|
|
$this->info("{$head}------------[结束]管理津贴结算------------".PHP_EOL);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* 初始化管理津贴
|
|
*
|
|
* @param \Illuminate\Support\Carbon $startAt
|
|
* @param \Illuminate\Support\Carbon $endAt
|
|
* @param int $count
|
|
* @return void
|
|
*/
|
|
protected function initializeManageSubsidies(Carbon $startAt, Carbon $endAt, $count = 200): void
|
|
{
|
|
$feeRate = app_settings('dealer.fee_rate');
|
|
|
|
$lastId = $this->getLastDealerId($startAt, $endAt);
|
|
|
|
do {
|
|
$dealers = Dealer::where('lvl', '>=', DealerLvl::Secondary)
|
|
->where('contracted_lvl_at', '<=', $endAt)
|
|
->forPageAfterId($count, $lastId, 'id')
|
|
->get();
|
|
|
|
$dealersCount = $dealers->count();
|
|
|
|
if ($dealersCount == 0) {
|
|
break;
|
|
}
|
|
|
|
$tz = now()->toDateTimeString();
|
|
$manageSubsidies = [];
|
|
|
|
foreach ($dealers as $dealer) {
|
|
$manageSubsidies[] = [
|
|
'user_id' => $dealer->user_id,
|
|
'total_amount' => 0,
|
|
'real_amount' => 0,
|
|
'fee' => 0,
|
|
'fee_rate' => $feeRate,
|
|
'start_at' => $startAt,
|
|
'end_at' => $endAt,
|
|
'lvl' => $dealer->lvl,
|
|
'is_manager' => $dealer->is_manager,
|
|
'status' => DealerManageSubsidyStatus::Pending,
|
|
'is_settle' => false,
|
|
'created_at' => $tz,
|
|
'updated_at' => $tz,
|
|
];
|
|
|
|
$lastId = $dealer->id;
|
|
}
|
|
|
|
DealerManageSubsidy::insert($manageSubsidies);
|
|
|
|
unset($dealers, $manageSubsidies);
|
|
} while ($dealersCount == $count);
|
|
}
|
|
|
|
/**
|
|
* 结算管理津贴
|
|
*
|
|
* @param \Illuminate\Support\Carbon $startAt
|
|
* @param \Illuminate\Support\Carbon $endAt
|
|
* @return void
|
|
*/
|
|
protected function settleManageSubsidies(Carbon $startAt, Carbon $endAt)
|
|
{
|
|
DealerManageSubsidy::where('start_at', $startAt)->where('end_at', $endAt)->where('is_settle', false)->chunkById(500, function ($subsidies) {
|
|
foreach ($subsidies as $subsidy) {
|
|
DB::transaction(function () use ($subsidy) {
|
|
$this->settleManageSubsidy($subsidy);
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* 结算单挑管理津贴
|
|
*
|
|
* @param \App\Models\DealerManageSubsidy
|
|
* @return void
|
|
*/
|
|
protected function settleManageSubsidy(DealerManageSubsidy $subsidy)
|
|
{
|
|
[$totalAmount, $remark] = $this->calculateTotalAmount($subsidy);
|
|
|
|
$feeRate = bcdiv($subsidy->fee_rate, '100', 5);
|
|
|
|
$fee = bcmul($totalAmount, $feeRate, 3);
|
|
$fee = round($fee, 2);
|
|
|
|
if (bccomp($totalAmount, '0', 2) === 0) {
|
|
$subsidy->status = DealerManageSubsidyStatus::Completed;
|
|
}
|
|
|
|
$subsidy->total_amount = $totalAmount;
|
|
$subsidy->real_amount = bcsub($totalAmount, $fee, 2);
|
|
$subsidy->fee = $fee;
|
|
$subsidy->remark = $remark;
|
|
$subsidy->is_settle = true;
|
|
$subsidy->save();
|
|
|
|
if (! $subsidy->isCompleted()) {
|
|
$subsidy->earning()->create([
|
|
'user_id' => $subsidy->user_id,
|
|
'lvl' => $subsidy->lvl,
|
|
'total_amount' => $subsidy->total_amount,
|
|
'total_earnings' => $subsidy->real_amount,
|
|
'fee' => $subsidy->fee,
|
|
'fee_rate' => $subsidy->fee_rate,
|
|
'settle_at' => now(),
|
|
'status' => DealerEarningStatus::Pending,
|
|
'remark' => sprintf(
|
|
'【%s - %s】%s',
|
|
$subsidy->start_at->format('Y/m/d H:i:s'),
|
|
$subsidy->end_at->format('Y/m/d H:i:s'),
|
|
$remark
|
|
),
|
|
]);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 计算补贴总金额
|
|
*
|
|
* @param \App\Models\DealerManageSubsidy
|
|
* @return void
|
|
*/
|
|
protected function calculateTotalAmount(DealerManageSubsidy $subsidy): array
|
|
{
|
|
$subsidyLogs = DealerManageSubsidyLog::select([
|
|
'product_id',
|
|
DB::raw('sum(sales_volume) as sales_volume'),
|
|
DB::raw('sum(total_amount) as total_amount'),
|
|
])->where(
|
|
'user_id', $subsidy->user_id
|
|
)->whereBetween(
|
|
'order_completed_at', [$subsidy->start_at, $subsidy->end_at]
|
|
)->groupBy('product_id')->get();
|
|
|
|
// 补贴总金额
|
|
$totalAmount = 0;
|
|
// 备注信息
|
|
$remark = '';
|
|
|
|
foreach ($subsidyLogs as $subsidyLog) {
|
|
$totalAmount = bcadd($totalAmount, $subsidyLog->total_amount, 2);
|
|
|
|
if ($remark !== '') {
|
|
$remark .= "\n";
|
|
}
|
|
|
|
$remark .= "【{$subsidyLog->product->name}】销量: {$subsidyLog->sales_volume}, 补贴金额: {$subsidyLog->total_amount}";
|
|
}
|
|
|
|
return [$totalAmount, $remark];
|
|
}
|
|
|
|
/**
|
|
* 获取给定时间端内的最后一个经销商补贴所属经销商的ID
|
|
*
|
|
* @param \Illuminate\Support\Carbon $startAt
|
|
* @param \Illuminate\Support\Carbon $endAt
|
|
* @return int|null
|
|
*/
|
|
protected function getLastDealerId(Carbon $startAt, Carbon $endAt): ?int
|
|
{
|
|
$lastManageSubsidy = DealerManageSubsidy::where('start_at', $startAt)
|
|
->where('end_at', $endAt)
|
|
->latest('id')
|
|
->first();
|
|
|
|
return $lastManageSubsidy?->dealer?->id;
|
|
}
|
|
|
|
/**
|
|
* 格式化时间
|
|
*
|
|
* @param float $milliseconds
|
|
* @return string
|
|
*/
|
|
protected function formatDuration($milliseconds): string
|
|
{
|
|
if ($milliseconds < 0.01) {
|
|
return round($milliseconds * 1000) . 'μs';
|
|
} elseif ($milliseconds >= 1000) {
|
|
return round($milliseconds / 1000, 2) . 's';
|
|
}
|
|
|
|
return $milliseconds . 'ms';
|
|
}
|
|
}
|