6
0
Fork 0
jiqu-library-server/app/Console/Commands/Dealer/ManagerSubsidySettleCommand...

194 lines
5.9 KiB
PHP

<?php
namespace App\Console\Commands\Dealer;
use App\Enums\DealerEarningStatus;
use App\Enums\DealerEarningType;
use App\Models\Dealer;
use App\Models\DealerEarning;
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 = $startAt->copy()->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}正在删除旧数据...");
DealerEarning::managerSubsidy()->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, $endAt->addMonthNoOverflow());
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();
$countDealers = $dealers->count();
if ($countDealers == 0) {
break;
}
$earnings = [];
$time = now()->toDateTimeString();
foreach ($dealers as $dealer) {
$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();
$description = '';
$totalAmount = 0;
foreach ($salesLogs as $log) {
$subsidy = bcmul($log->sales_volume, $log->product->manager_subsidy, 2);
$totalAmount = bcadd($totalAmount, $subsidy, 2);
if ($description !== '') {
$description .= "\n";
}
$description .= sprintf(
'【%s】销量: %s, 补贴金额: %s',
$log->product->name,
$log->sales_volume,
$subsidy
);
}
unset($salesLogs);
if (bccomp($totalAmount, '0', 2) === 1) {
// 计算手续费
$fee = bcmul($totalAmount, bcdiv($feeRate, '100', 10), 2);
$earnings[] = [
'user_id' => $dealer->user_id,
'total_amount' => $totalAmount,
'fee' => $fee,
'fee_rate' => $feeRate,
'type' => DealerEarningType::ManagerSubsidy,
'start_at' => $startAt,
'end_at' => $endAt,
'lvl' => $dealer->lvl,
'is_manager' => $dealer->is_manager,
'status' => DealerEarningStatus::Pending,
'description' => $description,
'created_at' => $time,
'updated_at' => $time,
];
}
$lastId = $dealer->id;
}
DealerEarning::insert($earnings);
Cache::put($cacheKey, $lastId, $endAt->addMonthNoOverflow());
unset($dealers, $earnings);
} while ($countDealers == $count);
Cache::forget($cacheKey);
}
/**
* 生成缓存的 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';
}
}