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