203 lines
6.2 KiB
PHP
203 lines
6.2 KiB
PHP
<?php
|
||
|
||
namespace App\Console\Commands\Dealer;
|
||
|
||
use App\Enums\DealerManagerSubsidyStatus;
|
||
use App\Models\Dealer;
|
||
use App\Models\DealerManagerSubsidy;
|
||
use Illuminate\Console\Command;
|
||
use Illuminate\Support\Carbon;
|
||
use Illuminate\Support\Facades\Cache;
|
||
use Illuminate\Support\Facades\DB;
|
||
|
||
class ManagerSubsidySettleCommand extends Command
|
||
{
|
||
/**
|
||
* The name and signature of the console command.
|
||
*
|
||
* @var string
|
||
*/
|
||
protected $signature = 'dealer:manager-subsidy-settle
|
||
{--force : 是否强制操作运行}';
|
||
|
||
/**
|
||
* The console command description.
|
||
*
|
||
* @var string
|
||
*/
|
||
protected $description = '结算上个月的管理者津贴';
|
||
|
||
/**
|
||
* Execute the console command.
|
||
*
|
||
* @return int
|
||
*/
|
||
public function handle()
|
||
{
|
||
$tz = now();
|
||
|
||
$startAt = $tz->copy()->subMonthNoOverflow()->startOfMonth();
|
||
$endAt = $tz->copy()->subMonthNoOverflow()->endOfMonth();
|
||
|
||
$head = '【'.$startAt->format('Y/m/d').'-'.$endAt->format('Y/m/d').'】';
|
||
|
||
$cacheKey = $this->cacheKey($startAt, $endAt);
|
||
|
||
// 如果不是强制执行,则需检查是否已结算过
|
||
if (! $this->option('force') && Cache::has($cacheKey)) {
|
||
return $this->warn("{$head}管理者津贴已结算");
|
||
}
|
||
|
||
$this->info("{$head}------------[开始]管理者津贴结算------------");
|
||
|
||
if ($this->option('force')) {
|
||
$this->info("{$head}正在删除旧数据...");
|
||
DealerManagerSubsidy::where('start_at', $startAt)->where('end_at', $endAt)->delete();
|
||
$this->info("{$head}数据删除成功");
|
||
}
|
||
|
||
$this->info("{$head}数据写入中...");
|
||
$this->settle($startAt, $endAt, 500);
|
||
$this->info("{$head}写入成功, 总耗时: ".$this->formatDuration($tz->diffInMilliseconds(now(), false)));
|
||
|
||
$this->info("{$head}------------[结束]管理者津贴结算------------".PHP_EOL);
|
||
|
||
Cache::put($cacheKey, 1, $tz->endOfMonth());
|
||
|
||
return 0;
|
||
}
|
||
|
||
/**
|
||
* 管理津贴结算结算
|
||
*
|
||
* @param \Illuminate\Support\Carbon $startAt
|
||
* @param \Illuminate\Support\Carbon $endAt
|
||
* @param int $count
|
||
* @return void
|
||
*/
|
||
protected function settle(Carbon $startAt, Carbon $endAt, int $count = 200): void
|
||
{
|
||
$feeRate = app_settings('dealer.fee_rate');
|
||
|
||
$lastId = Cache::get(
|
||
$cacheKey = $this->cacheKey($startAt, $endAt).':last_id'
|
||
);
|
||
|
||
do {
|
||
$dealers = Dealer::where('is_manager', 1)
|
||
->forPageAfterId($count, $lastId, 'id')
|
||
->get();
|
||
|
||
$dealersCount = $dealers->count();
|
||
|
||
if ($dealersCount == 0) {
|
||
break;
|
||
}
|
||
|
||
$tz = now()->toDateTimeString();
|
||
|
||
$earnings = [];
|
||
|
||
foreach ($dealers as $dealer) {
|
||
[$totalAmount, $remark] = $this->calculateTotalAmount($dealer, $startAt, $endAt);
|
||
|
||
// 如果 补贴总金额 > 0,则添加管理者补贴记录
|
||
if (bccomp($totalAmount, '0', 2) === 1) {
|
||
// 计算手续费
|
||
$fee = bcmul($totalAmount, bcdiv($feeRate, '100', 10), 2);
|
||
|
||
$earnings[] = [
|
||
'user_id' => $dealer->user_id,
|
||
'total_amount' => $totalAmount,
|
||
'real_amount' => bcsub($totalAmount, $fee, 2),
|
||
'fee' => $fee,
|
||
'fee_rate' => $feeRate,
|
||
'start_at' => $startAt,
|
||
'end_at' => $endAt,
|
||
'lvl' => $dealer->lvl,
|
||
'is_manager' => $dealer->is_manager,
|
||
'status' => DealerManagerSubsidyStatus::Pending,
|
||
'remark' => $remark,
|
||
'created_at' => $tz,
|
||
'updated_at' => $tz,
|
||
];
|
||
}
|
||
|
||
$lastId = $dealer->id;
|
||
}
|
||
|
||
DealerManagerSubsidy::insert($earnings);
|
||
|
||
Cache::put($cacheKey, $lastId, $endAt->addMonthNoOverflow());
|
||
|
||
unset($dealers, $earnings);
|
||
} while ($dealersCount == $count);
|
||
|
||
Cache::forget($cacheKey);
|
||
}
|
||
|
||
/**
|
||
* 计算补贴总金额
|
||
*
|
||
* @param \App\Models\Dealer
|
||
* @param \Illuminate\Support\Carbon $startAt
|
||
* @param \Illuminate\Support\Carbon $endAt
|
||
* @return array
|
||
*/
|
||
protected function calculateTotalAmount(Dealer $dealer, Carbon $startAt, Carbon $endAt): array
|
||
{
|
||
$salesLogs = $dealer->managerSalesLogs()
|
||
->with(['product'])
|
||
->select('product_id', DB::raw('sum(sales_volume) as sales_volume'))
|
||
->whereBetween('order_completed_at', [$startAt, $endAt])
|
||
->groupBy('product_id')
|
||
->get();
|
||
// 补贴总金额
|
||
$totalAmount = 0;
|
||
// 备注信息
|
||
$remark = '';
|
||
|
||
foreach ($salesLogs as $salesLog) {
|
||
$amount = bcmul($salesLog->sales_volume, $salesLog->product->manager_subsidy, 2);
|
||
$totalAmount = bcadd($totalAmount, $amount, 2);
|
||
|
||
if ($remark !== '') {
|
||
$remark .= "\n";
|
||
}
|
||
|
||
$remark .= "【{$salesLog->product->name}】销量: {$salesLog->sales_volume}, 补贴金额: {$amount}";
|
||
}
|
||
|
||
return [$totalAmount, $remark];
|
||
}
|
||
|
||
/**
|
||
* 生成缓存的 key
|
||
*
|
||
* @param \Illuminate\Support\Carbon $startAt
|
||
* @param \Illuminate\Support\Carbon $endAt
|
||
* @return void
|
||
*/
|
||
protected function cacheKey(Carbon $startAt, Carbon $endAt)
|
||
{
|
||
return $startAt->format('Ymd').'_'.$endAt->format('Ymd').'_dealer_manager_subsidy';
|
||
}
|
||
|
||
/**
|
||
* 格式化时间
|
||
*
|
||
* @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';
|
||
}
|
||
}
|