From 55b8e88919548c7b1c51da43b641c9391e674594 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=9D=99?= Date: Sat, 15 Jan 2022 14:32:08 +0800 Subject: [PATCH] =?UTF-8?q?=E7=AE=A1=E7=90=86=E8=80=85=E8=A1=A5=E8=B4=B4?= =?UTF-8?q?=E7=BB=93=E7=AE=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Dealer/ManagerSubsidySettleCommand.php | 172 ++++++++++++++++++ app/Models/Dealer.php | 8 + app/Models/DealerEarning.php | 17 ++ app/Models/DealerManageSubsidyLog.php | 8 + app/Models/DealerManagerSalesLog.php | 8 + ...dd_is_manager_to_dealer_earnings_table.php | 32 ++++ ...33557_add_lvl_to_dealer_earnings_table.php | 32 ++++ ...d_description_to_dealer_earnings_table.php | 32 ++++ 8 files changed, 309 insertions(+) create mode 100644 app/Console/Commands/Dealer/ManagerSubsidySettleCommand.php create mode 100644 database/migrations/2022_01_15_133549_add_is_manager_to_dealer_earnings_table.php create mode 100644 database/migrations/2022_01_15_133557_add_lvl_to_dealer_earnings_table.php create mode 100644 database/migrations/2022_01_15_141756_add_description_to_dealer_earnings_table.php diff --git a/app/Console/Commands/Dealer/ManagerSubsidySettleCommand.php b/app/Console/Commands/Dealer/ManagerSubsidySettleCommand.php new file mode 100644 index 00000000..3bc785c3 --- /dev/null +++ b/app/Console/Commands/Dealer/ManagerSubsidySettleCommand.php @@ -0,0 +1,172 @@ +copy()->subMonthNoOverflow()->startOfMonth(); + $endAt = $startAt->copy()->endOfMonth(); + + $head = '【'.$startAt->format('Y/m/d').'-'.$endAt->format('Y/m/d').'】'; + + // 如果不是强制执行,则需检查是否已结算过 + if (! $this->option('force') && Cache::has($this->cacheKey($startAt, $endAt))) { + 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); + $this->info("{$head}写入成功, 总耗时: ".$this->formatDuration($tz->diffInMilliseconds(now(), false))); + + $this->info("{$head}------------[结束]管理者津贴结算------------".PHP_EOL); + + // 缓存31天 + Cache::put($this->cacheKey($startAt, $endAt), 1, 2678400); + + return 0; + } + + /** + * 管理津贴结算结算 + * + * @param \Illuminate\Support\Carbon $startAt + * @param \Illuminate\Support\Carbon $endAt + * @return void + */ + protected function settle(Carbon $startAt, Carbon $endAt): void + { + $feeRate = app_settings('dealer.fee_rate'); + + Dealer::where('is_manager', 1)->chunkById(200, function ($dealers) use ($startAt, $endAt, $feeRate) { + $time = now()->toDateTimeString(); + + $earnings = []; + + foreach ($dealers as $dealer) { + $salesLogs = $dealer->managerSalesLog() + ->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 + ); + } + + + 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, + ]; + } + + unset($salesLogs); + } + + DealerEarning::insert($earnings); + + unset($earnings); + }); + } + + /** + * 生成缓存的 key + * + * @param \Illuminate\Support\Carbon $startAt + * @param \Illuminate\Support\Carbon $endAt + * @return void + */ + protected function cacheKey(Carbon $startAt, Carbon $endAt) + { + $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'; + } +} diff --git a/app/Models/Dealer.php b/app/Models/Dealer.php index 418c93d0..af1710d5 100644 --- a/app/Models/Dealer.php +++ b/app/Models/Dealer.php @@ -28,6 +28,14 @@ class Dealer extends Model 'is_manager', ]; + /** + * 属于此经销商的管理者津贴 + */ + public function managerSalesLog() + { + return $this->hasMany(DealerManagerSalesLog::class, 'user_id', 'user_id'); + } + public function getLvlTextAttribute() { return $this->lvl->text(); diff --git a/app/Models/DealerEarning.php b/app/Models/DealerEarning.php index 1ebaf5e4..0cbde1fc 100644 --- a/app/Models/DealerEarning.php +++ b/app/Models/DealerEarning.php @@ -4,6 +4,7 @@ namespace App\Models; use App\Enums\DealerEarningStatus; use App\Enums\DealerEarningType; +use App\Enums\DealerLvl; use Illuminate\Database\Eloquent\Model; class DealerEarning extends Model @@ -13,6 +14,8 @@ class DealerEarning extends Model 'end_at' => 'datetime', 'type' => DealerEarningType::class, 'status' => DealerEarningStatus::class, + 'lvl' => DealerLvl::class, + 'is_manager' => 'bool', 'completed_at' => 'datetime', ]; @@ -24,7 +27,10 @@ class DealerEarning extends Model 'type', 'start_at', 'end_at', + 'lvl', + 'is_manager', 'status', + 'description', 'completed_at', ]; @@ -38,4 +44,15 @@ class DealerEarning extends Model { return $query->where('type', DealerEarningType::ManageSubsidy); } + + /** + * 仅查询管理者补贴 + * + * @param \Illuminate\Database\Eloquent\Builder $query + * @return \Illuminate\Database\Eloquent\Builder + */ + public function scopeManagerSubsidy($query) + { + return $query->where('type', DealerEarningType::ManagerSubsidy); + } } diff --git a/app/Models/DealerManageSubsidyLog.php b/app/Models/DealerManageSubsidyLog.php index 3098acb5..44a12fd2 100644 --- a/app/Models/DealerManageSubsidyLog.php +++ b/app/Models/DealerManageSubsidyLog.php @@ -21,4 +21,12 @@ class DealerManageSubsidyLog extends Model 'total_amount', 'order_completed_at', ]; + + /** + * 此管理津贴所属的经销商 + */ + public function dealer() + { + return $this->belongsTo(Dealer::class, 'user_id', 'user_id'); + } } diff --git a/app/Models/DealerManagerSalesLog.php b/app/Models/DealerManagerSalesLog.php index 5b10d68c..47451de7 100644 --- a/app/Models/DealerManagerSalesLog.php +++ b/app/Models/DealerManagerSalesLog.php @@ -23,4 +23,12 @@ class DealerManagerSalesLog extends Model 'sales_volume', 'order_completed_at', ]; + + /** + * 此商品销售业绩所属的商品 + */ + public function product() + { + return $this->belongsTo(DealerProduct::class, 'product_id'); + } } diff --git a/database/migrations/2022_01_15_133549_add_is_manager_to_dealer_earnings_table.php b/database/migrations/2022_01_15_133549_add_is_manager_to_dealer_earnings_table.php new file mode 100644 index 00000000..aeb9506e --- /dev/null +++ b/database/migrations/2022_01_15_133549_add_is_manager_to_dealer_earnings_table.php @@ -0,0 +1,32 @@ +boolean('is_manager')->default(false)->comment('是否是管理者'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('dealer_earnings', function (Blueprint $table) { + $table->dropColumn('is_manager'); + }); + } +} diff --git a/database/migrations/2022_01_15_133557_add_lvl_to_dealer_earnings_table.php b/database/migrations/2022_01_15_133557_add_lvl_to_dealer_earnings_table.php new file mode 100644 index 00000000..e0c925c7 --- /dev/null +++ b/database/migrations/2022_01_15_133557_add_lvl_to_dealer_earnings_table.php @@ -0,0 +1,32 @@ +tinyInteger('lvl')->comment('经销商等级'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('dealer_earnings', function (Blueprint $table) { + $table->dropColumn('lvl'); + }); + } +} diff --git a/database/migrations/2022_01_15_141756_add_description_to_dealer_earnings_table.php b/database/migrations/2022_01_15_141756_add_description_to_dealer_earnings_table.php new file mode 100644 index 00000000..0e84569e --- /dev/null +++ b/database/migrations/2022_01_15_141756_add_description_to_dealer_earnings_table.php @@ -0,0 +1,32 @@ +text('description')->nullable()->comment('描述'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('dealer_earnings', function (Blueprint $table) { + $table->dropColumn('description'); + }); + } +}