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'; } }