From 587fdcf41526cffdae04c2c6c9a69a72cf4c76c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=9D=99?= Date: Tue, 18 Jan 2022 20:59:58 +0800 Subject: [PATCH] =?UTF-8?q?=E7=BB=8F=E9=94=80=E5=95=86=E7=BB=8F=E7=BB=93?= =?UTF-8?q?=E7=AE=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Dealer/ManageSubsidySettleCommand.php | 61 ++- .../Dealer/ManagerSubsidySettleCommand.php | 60 ++- .../Commands/Dealer/OrderProcessCommand.php | 54 ++- .../Dealer/PurchaseSubsidySettleCommand.php | 395 ++++++++++++++++++ app/Console/Kernel.php | 9 +- app/Enums/DealerManageSubsidyStatus.php | 1 + app/Enums/DealerManagerSubsidyStatus.php | 1 + .../DealerPurchaseSubsidySettleState.php | 9 + app/Enums/DealerPurchaseSubsidyStatus.php | 8 + app/Models/DealerManageSubsidy.php | 10 + app/Models/DealerManagerSubsidy.php | 10 + app/Models/DealerOrder.php | 10 +- app/Models/DealerPurchaseSubsidy.php | 63 +++ app/Models/DealerPurchaseSubsidyLog.php | 15 + app/Providers/AppServiceProvider.php | 1 + ...create_dealer_purchase_subsidies_table.php | 50 +++ ...ate_dealer_purchase_subsidy_logs_table.php | 37 ++ 17 files changed, 745 insertions(+), 49 deletions(-) create mode 100644 app/Console/Commands/Dealer/PurchaseSubsidySettleCommand.php create mode 100644 app/Enums/DealerPurchaseSubsidySettleState.php create mode 100644 app/Enums/DealerPurchaseSubsidyStatus.php create mode 100644 app/Models/DealerPurchaseSubsidy.php create mode 100644 app/Models/DealerPurchaseSubsidyLog.php create mode 100644 database/migrations/2022_01_17_095411_create_dealer_purchase_subsidies_table.php create mode 100644 database/migrations/2022_01_17_100317_create_dealer_purchase_subsidy_logs_table.php diff --git a/app/Console/Commands/Dealer/ManageSubsidySettleCommand.php b/app/Console/Commands/Dealer/ManageSubsidySettleCommand.php index 9cebb9a7..06ec3431 100644 --- a/app/Console/Commands/Dealer/ManageSubsidySettleCommand.php +++ b/app/Console/Commands/Dealer/ManageSubsidySettleCommand.php @@ -2,11 +2,14 @@ namespace App\Console\Commands\Dealer; +use App\Enums\DealerEarningStatus; use App\Enums\DealerLvl; use App\Enums\DealerManageSubsidyStatus; +use App\Enums\DealerOrderSettleState; use App\Models\Dealer; use App\Models\DealerManageSubsidy; use App\Models\DealerManageSubsidyLog; +use App\Models\DealerOrder; use Illuminate\Console\Command; use Illuminate\Support\Carbon; use Illuminate\Support\Facades\DB; @@ -64,6 +67,16 @@ class ManageSubsidySettleCommand extends Command $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}管理津贴初始化..."); @@ -96,6 +109,7 @@ class ManageSubsidySettleCommand extends Command do { $dealers = Dealer::where('lvl', '>=', DealerLvl::Secondary) + ->where('contracted_lvl_at', '<=', $endAt) ->forPageAfterId($count, $lastId, 'id') ->get(); @@ -105,8 +119,8 @@ class ManageSubsidySettleCommand extends Command break; } - $manageSubsidies = []; $tz = now()->toDateTimeString(); + $manageSubsidies = []; foreach ($dealers as $dealer) { $manageSubsidies[] = [ @@ -145,7 +159,9 @@ class ManageSubsidySettleCommand extends Command { DealerManageSubsidy::where('start_at', $startAt)->where('end_at', $endAt)->where('is_settle', false)->chunkById(500, function ($subsidies) { foreach ($subsidies as $subsidy) { - $this->settleManageSubsidy($subsidy); + DB::transaction(function () use ($subsidy) { + $this->settleManageSubsidy($subsidy); + }); } }); } @@ -160,15 +176,40 @@ class ManageSubsidySettleCommand extends Command { [$totalAmount, $remark] = $this->calculateTotalAmount($subsidy); - $fee = bcmul($totalAmount, bcdiv($subsidy->fee_rate, '100', 5), 2); + $feeRate = bcdiv($subsidy->fee_rate, '100', 5); - $subsidy->forceFill([ - 'total_amount' => $totalAmount, - 'real_amount' => bcsub($totalAmount, $fee, 2), - 'fee' => $fee, - 'remark' => $remark, - 'is_settle' => true, - ])->save(); + $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 + ), + ]); + } } /** diff --git a/app/Console/Commands/Dealer/ManagerSubsidySettleCommand.php b/app/Console/Commands/Dealer/ManagerSubsidySettleCommand.php index 53fc13a4..722fb074 100644 --- a/app/Console/Commands/Dealer/ManagerSubsidySettleCommand.php +++ b/app/Console/Commands/Dealer/ManagerSubsidySettleCommand.php @@ -2,10 +2,13 @@ namespace App\Console\Commands\Dealer; +use App\Enums\DealerEarningStatus; use App\Enums\DealerManagerSubsidyStatus; +use App\Enums\DealerOrderSettleState; use App\Models\Dealer; use App\Models\DealerManagerSalesLog; use App\Models\DealerManagerSubsidy; +use App\Models\DealerOrder; use Illuminate\Console\Command; use Illuminate\Support\Carbon; use Illuminate\Support\Facades\DB; @@ -40,6 +43,16 @@ class ManagerSubsidySettleCommand extends Command $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}管理者津贴初始化..."); @@ -81,8 +94,8 @@ class ManagerSubsidySettleCommand extends Command break; } - $managerSubsidies = []; $tz = now()->toDateTimeString(); + $managerSubsidies = []; foreach ($dealers as $dealer) { $managerSubsidies[] = [ @@ -121,7 +134,9 @@ class ManagerSubsidySettleCommand extends Command { DealerManagerSubsidy::where('start_at', $startAt)->where('end_at', $endAt)->where('is_settle', false)->chunkById(500, function ($subsidies) { foreach ($subsidies as $subsidy) { - $this->settleManagerSubsidy($subsidy); + DB::transaction(function () use ($subsidy) { + $this->settleManagerSubsidy($subsidy); + }); } }); } @@ -136,15 +151,40 @@ class ManagerSubsidySettleCommand extends Command { [$totalAmount, $remark] = $this->calculateTotalAmount($subsidy); - $fee = bcmul($totalAmount, bcdiv($subsidy->fee_rate, '100', 5), 2); + $feeRate = bcdiv($subsidy->fee_rate, '100', 5); - $subsidy->forceFill([ - 'total_amount' => $totalAmount, - 'real_amount' => bcsub($totalAmount, $fee, 2), - 'fee' => $fee, - 'remark' => $remark, - 'is_settle' => true, - ])->save(); + $fee = bcmul($totalAmount, $feeRate, 3); + $fee = round($fee, 2); + + if (bccomp($totalAmount, '0', 2) === 0) { + $subsidy->status = DealerManagerSubsidyStatus::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 + ), + ]); + } } /** diff --git a/app/Console/Commands/Dealer/OrderProcessCommand.php b/app/Console/Commands/Dealer/OrderProcessCommand.php index 7019aa1d..ad189495 100644 --- a/app/Console/Commands/Dealer/OrderProcessCommand.php +++ b/app/Console/Commands/Dealer/OrderProcessCommand.php @@ -40,33 +40,41 @@ class OrderProcessCommand extends Command */ public function handle() { - DealerOrder::where( - 'settle_state', - DealerOrderSettleState::Pending - )->whereIn('status', [ - DealerOrderStatus::Paid, - DealerOrderStatus::Shipped, - DealerOrderStatus::Completed, - ])->chunkById(200, function ($orders) { - $orders->load([ - 'dealer.userInfo', - 'products.productManageSubsidyRules', - ]); + do { + $page = 0; - foreach ($orders as $order) { - try { - DB::beginTransaction(); + DealerOrder::where( + 'settle_state', + DealerOrderSettleState::Pending + )->whereIn('status', [ + DealerOrderStatus::Paid, + DealerOrderStatus::Shipped, + DealerOrderStatus::Completed, + ])->chunkById(200, function ($orders) use (&$page) { + $orders->load([ + 'dealer.userInfo', + 'products.productManageSubsidyRules', + ]); - $this->handleDealerOrder($order); - - DB::commit(); - } catch (Throwable $e) { - DB::rollBack(); - - report($e); + foreach ($orders as $order) { + try { + DB::transaction(function () use ($order) { + $this->handleDealerOrder($order); + }); + } catch (Throwable $e) { + report($e); + } } + + $page += 1; + }); + + if ($page === 0) { + sleep(30); + } elseif ($page === 1) { + sleep(5); } - }); + } while (true); return 0; } diff --git a/app/Console/Commands/Dealer/PurchaseSubsidySettleCommand.php b/app/Console/Commands/Dealer/PurchaseSubsidySettleCommand.php new file mode 100644 index 00000000..7e309aa3 --- /dev/null +++ b/app/Console/Commands/Dealer/PurchaseSubsidySettleCommand.php @@ -0,0 +1,395 @@ +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 = $startAt->copy()->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}------------[开始]进货补贴结算------------"); + + $this->info("{$head}进货补贴初始化..."); + $this->initializePurchaseSubsidies($startAt, $endAt, 200); + $this->info("{$head}进货补贴初始化完成".PHP_EOL); + + $this->info("{$head}扣除上级的进货补贴..."); + $this->deductPurchaseSubsidies($startAt, $endAt, 200); + $this->info("{$head}扣除上级的进货补贴完成".PHP_EOL); + + $this->info("{$head}计算手续费..."); + $this->calculateFeeOfPurchaseSubsidies($startAt, $endAt, 200); + $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 calculateFeeOfPurchaseSubsidies(Carbon $startAt, Carbon $endAt, int $count = 200): void + { + DealerPurchaseSubsidy::where([ + 'start_at' => $startAt, + 'end_at' => $endAt, + 'settle_state' => DealerPurchaseSubsidySettleState::Processed, + ])->chunkById($count, function ($purchaseSubsidies) { + foreach ($purchaseSubsidies as $purchaseSubsidy) { + DB::transaction(function () use ($purchaseSubsidy) { + $this->calculateFeeOfPurchaseSubsidy($purchaseSubsidy); + }); + } + }); + } + + /** + * 计算进货补贴手续费 + * + * @param \App\Models\DealerPurchaseSubsidy $purchaseSubsidy + * @return void + */ + protected function calculateFeeOfPurchaseSubsidy(DealerPurchaseSubsidy $purchaseSubsidy) + { + if (bccomp($purchaseSubsidy->total_amount, '0') === 1) { + $feeRate = bcdiv($purchaseSubsidy->fee_rate, '100', 5); + + $fee = bcmul($purchaseSubsidy->total_amount, $feeRate, 3); + $fee = round($fee, 2); + + $purchaseSubsidy->fee = $fee; + $purchaseSubsidy->real_amount = bcsub($purchaseSubsidy->total_amount, $fee, 2); + } else { + $purchaseSubsidy->status = DealerPurchaseSubsidyStatus::Completed; + } + $purchaseSubsidy->settle_state = DealerPurchaseSubsidySettleState::Completed; + $purchaseSubsidy->save(); + + if (! $purchaseSubsidy->isCompleted()) { + $remark = sprintf( + '【%s - %s】销售业绩: %s, 补贴比例: %s%%', + $purchaseSubsidy->start_at->format('Y/m/d H:i:s'), + $purchaseSubsidy->end_at->format('Y/m/d H:i:s'), + $purchaseSubsidy->total_purchase_amount, + $purchaseSubsidy->subsidy_rate + ); + + $purchaseSubsidy->earning()->create([ + 'user_id' => $purchaseSubsidy->user_id, + 'lvl' => $purchaseSubsidy->lvl, + 'total_amount' => $purchaseSubsidy->total_amount, + 'total_earnings' => $purchaseSubsidy->real_amount, + 'fee' => $purchaseSubsidy->fee, + 'fee_rate' => $purchaseSubsidy->fee_rate, + 'settle_at' => now(), + 'status' => DealerEarningStatus::Pending, + 'remark' => $remark, + ]); + } + } + + /** + * 扣除上级的进货补贴 + * + * @param \Illuminate\Support\Carbon $startAt + * @param \Illuminate\Support\Carbon $endAt + * @param int $count + * @return void + */ + protected function deductPurchaseSubsidies(Carbon $startAt, Carbon $endAt, int $count = 200): void + { + DealerPurchaseSubsidy::where([ + 'start_at' => $startAt, + 'end_at' => $endAt, + 'settle_state' => DealerPurchaseSubsidySettleState::Pending, + ])->chunkById($count, function ($purchaseSubsidies) { + foreach ($purchaseSubsidies as $purchaseSubsidy) { + DB::transaction(function () use ($purchaseSubsidy) { + $this->deductPurchaseSubsidy($purchaseSubsidy); + }); + } + }); + } + + /** + * 扣除上级的采购补贴总额 + * + * @param \AppModels\DealerPurchaseSubsidy $purchaseSubsidy + * @return void + */ + protected function deductPurchaseSubsidy(DealerPurchaseSubsidy $purchaseSubsidy) + { + // 扣除下级的进货补贴 + if ($purchaseSubsidy->payer_id && bccomp($purchaseSubsidy->total_amount, '0', 2) === 1) { + $payerPurchaseSubsidy = DealerPurchaseSubsidy::where([ + 'user_id' => $purchaseSubsidy->payer_id, + 'start_at' => $purchaseSubsidy->start_at, + 'end_at' => $purchaseSubsidy->end_at, + ])->first(); + + if ($payerPurchaseSubsidy) { + $payerPurchaseSubsidy->decrement('total_amount', $purchaseSubsidy->total_amount); + + $payerPurchaseSubsidy->logs()->create([ + 'purchase_subsidy_id' => $payerPurchaseSubsidy->id, + 'change_from_purchase_subsidy_id' => $purchaseSubsidy->id, + 'change_amount' => bcmul($purchaseSubsidy->total_amount, '-1', 2), + 'remark' => '扣除下级的进货补贴', + ]); + } + } + + $purchaseSubsidy->update([ + 'settle_state' => DealerPurchaseSubsidySettleState::Processed, + ]); + } + + /** + * 初始化进货补贴 + * + * @param \Illuminate\Support\Carbon $startAt + * @param \Illuminate\Support\Carbon $endAt + * @param int $count + * @return void + */ + protected function initializePurchaseSubsidies(Carbon $startAt, Carbon $endAt, int $count = 200) + { + // 手续费比例 + $feeRate = app_settings('dealer.fee_rate'); + // 采购补贴规则 + $purchaseRules = (array) app_settings('dealer.purchase_rules'); + + $lastId = $this->getLastDealerId($startAt, $endAt); + + do { + $dealers = Dealer::with(['userInfo']) + ->where('contracted_lvl_at', '<=', $endAt) + ->where('lvl', '>=', DealerLvl::Contracted->value) + ->forPageAfterId($count, $lastId, 'id') + ->get(); + + $dealersCount = $dealers->count(); + + if ($dealersCount == 0) { + break; + } + + foreach ($dealers as $dealer) { + DB::transaction(function () use ($dealer, $startAt, $endAt, $feeRate, $purchaseRules) { + $this->initializePurchaseSubsidy($dealer, $startAt, $endAt, $feeRate, $purchaseRules); + }); + + $lastId = $dealer->id; + } + + unset($dealers); + } while ($dealersCount == $count); + } + + /** + * 初始化进货补贴 + * + * @param Dealer $dealer + * @param Carbon $startAt + * @param Carbon $endAt + * @param float $feeRate + * @param array $purchaseRules + * @return void + */ + protected function initializePurchaseSubsidy(Dealer $dealer, Carbon $startAt, Carbon $endAt, $feeRate, array $purchaseRules) + { + // 进货总额 + $totalPurchaseAmount = DealerPurchaseLog::query() + ->whereBetween('order_completed_at', [$startAt, $endAt]) + ->where('path', 'like', "{$dealer->userInfo->full_path}%") + ->sum('total_amount'); + + // 如果没有进货总额,则返回 + if (bccomp($totalPurchaseAmount, '0', 2) <= 0) { + return; + } + + // 进货补贴比例 + $subsidyRate = $this->filterSubsidyRate($totalPurchaseAmount, $purchaseRules); + + // 补贴总额 + $totalSubsidy = bcmul($totalPurchaseAmount, bcdiv($subsidyRate, '100', 5), 3); + $totalSubsidy = round($totalSubsidy, 2); + + $purchaseSubsidy = DealerPurchaseSubsidy::create([ + 'user_id' => $dealer->user_id, + 'payer_id' => $this->nearestContractedDealer($dealer, $endAt)?->user_id, + 'lvl' => $dealer->lvl, + 'total_purchase_amount' => $totalPurchaseAmount, + 'subsidy_rate' => $subsidyRate, + 'total_subsidy' => $totalSubsidy, + 'total_amount' => $totalSubsidy, + 'real_amount' => 0, + 'fee' => 0, + 'fee_rate' => $feeRate, + 'start_at' => $startAt, + 'end_at' => $endAt, + 'settle_state' => DealerPurchaseSubsidySettleState::Pending, + 'status' => DealerPurchaseSubsidyStatus::Pending, + ]); + + if (bccomp($purchaseSubsidy->total_subsidy, '0', 2) === 1) { + $purchaseSubsidy->logs()->create([ + 'purchase_subsidy_id' => $purchaseSubsidy->id, + 'change_from_purchase_subsidy_id' => null, + 'change_amount' => $purchaseSubsidy->total_subsidy, + 'remark' => '进货补贴总额', + ]); + } + } + + /** + * 进货补贴比例 + * + * @param float $totalPurchaseAmount + * @param array $purchaseRules + * @return float + */ + protected function filterSubsidyRate($totalPurchaseAmount, array $purchaseRules) + { + $rate = '0'; + + foreach ($purchaseRules as $rule) { + if (bccomp($totalPurchaseAmount, bcmul($rule['price'], '10000'), 2) === -1) { + continue; + } + + if (bccomp($rule['rate'], $rate, 5) === 1) { + $rate = $rule['rate']; + } + } + + return $rate; + } + + /** + * 获取最近的上级签约经销商 + * + * @param \App\Models\Dealer $dealer + * @param \Illuminate\Support\Carbon $startAt + * @return \App\Models\Dealer|null + */ + protected function nearestContractedDealer(Dealer $dealer, Carbon $endAt): ?Dealer + { + foreach ($dealer->getDealers() as $_dealer) { + // 如果当前经销商等级小于签约,则跳过 + if ($_dealer->lvl->value < DealerLvl::Contracted->value) { + continue; + } + + if ($_dealer->contracted_lvl_at?->lte($endAt)) { + return $_dealer; + } + } + + return null; + } + + /** + * 获取给定时间端内的最后一个进货补贴所属经销商的ID + * + * @param \Illuminate\Support\Carbon $startAt + * @param \Illuminate\Support\Carbon $endAt + * @return int|null + */ + protected function getLastDealerId(Carbon $startAt, Carbon $endAt): ?int + { + $lastPurchaseSubsidy = DealerPurchaseSubsidy::where('start_at', $startAt) + ->where('end_at', $endAt) + ->latest('id') + ->first(); + + return $lastPurchaseSubsidy?->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'; + } +} diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index 69914e99..a86e5ce0 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -24,7 +24,14 @@ class Kernel extends ConsoleKernel */ protected function schedule(Schedule $schedule) { - // $schedule->command('inspire')->hourly(); + $schedule->command('dealer:manage-subsidy-settle') + ->twiceMonthly(5, 20, '1:00'); + + $schedule->command('dealer:purchase-subsidy-settle') + ->twiceMonthly(5, 20, '2:00'); + + $schedule->command('dealer:manager-subsidy-settle') + ->monthlyOn(1, '3:00'); } /** diff --git a/app/Enums/DealerManageSubsidyStatus.php b/app/Enums/DealerManageSubsidyStatus.php index f98d6287..2a6ed321 100644 --- a/app/Enums/DealerManageSubsidyStatus.php +++ b/app/Enums/DealerManageSubsidyStatus.php @@ -4,4 +4,5 @@ namespace App\Enums; enum DealerManageSubsidyStatus: int { case Pending = 0; + case Completed = 5; } diff --git a/app/Enums/DealerManagerSubsidyStatus.php b/app/Enums/DealerManagerSubsidyStatus.php index 36ce1864..8400c0a1 100644 --- a/app/Enums/DealerManagerSubsidyStatus.php +++ b/app/Enums/DealerManagerSubsidyStatus.php @@ -4,4 +4,5 @@ namespace App\Enums; enum DealerManagerSubsidyStatus: int { case Pending = 0; + case Completed = 5; } diff --git a/app/Enums/DealerPurchaseSubsidySettleState.php b/app/Enums/DealerPurchaseSubsidySettleState.php new file mode 100644 index 00000000..2514477b --- /dev/null +++ b/app/Enums/DealerPurchaseSubsidySettleState.php @@ -0,0 +1,9 @@ +belongsTo(Dealer::class, 'user_id', 'user_id'); } + + public function earning() + { + return $this->morphOne(DealerEarning::class, 'earningable'); + } + + public function isCompleted() + { + return $this->status === DealerManageSubsidyStatus::Completed; + } } diff --git a/app/Models/DealerManagerSubsidy.php b/app/Models/DealerManagerSubsidy.php index a1f55e7f..caea0024 100644 --- a/app/Models/DealerManagerSubsidy.php +++ b/app/Models/DealerManagerSubsidy.php @@ -45,4 +45,14 @@ class DealerManagerSubsidy extends Model { return $this->belongsTo(Dealer::class, 'user_id', 'user_id'); } + + public function earning() + { + return $this->morphOne(DealerEarning::class, 'earningable'); + } + + public function isCompleted() + { + return $this->status === DealerManagerSubsidyStatus::Completed; + } } diff --git a/app/Models/DealerOrder.php b/app/Models/DealerOrder.php index 70482645..bbb59909 100644 --- a/app/Models/DealerOrder.php +++ b/app/Models/DealerOrder.php @@ -47,11 +47,6 @@ class DealerOrder extends Model 'allocated_at', //分配时间 ]; - public function getOrderStatusAttribute() - { - return $this->status->value; - } - /** * 获取待确认订单 */ @@ -147,6 +142,11 @@ class DealerOrder extends Model return $this->consignor_id == $userId; } + public function getOrderStatusAttribute() + { + return $this->status->value; + } + /** * 是否待确认订单 * diff --git a/app/Models/DealerPurchaseSubsidy.php b/app/Models/DealerPurchaseSubsidy.php new file mode 100644 index 00000000..ffb86130 --- /dev/null +++ b/app/Models/DealerPurchaseSubsidy.php @@ -0,0 +1,63 @@ + DealerLvl::None, + 'settle_state' => DealerPurchaseSubsidySettleState::Pending, + 'status' => DealerPurchaseSubsidyStatus::Pending, + ]; + + protected $casts = [ + 'lvl' => DealerLvl::class, + 'start_at' => 'datetime', + 'end_at' => 'datetime', + 'settle_state' => DealerPurchaseSubsidySettleState::class, + 'status' => DealerPurchaseSubsidyStatus::class, + ]; + + protected $fillable = [ + 'user_id', + 'payer_id', + 'lvl', + 'total_purchase_amount', + 'subsidy_rate', + 'total_subsidy', + 'total_amount', + 'real_amount', + 'fee', + 'fee_rate', + 'start_at', + 'end_at', + 'settle_state', + 'status', + 'remark', + ]; + + public function dealer() + { + return $this->belongsTo(Dealer::class, 'user_id', 'user_id'); + } + + public function logs() + { + return $this->hasMany(DealerPurchaseSubsidyLog::class, 'purchase_subsidy_id'); + } + + public function earning() + { + return $this->morphOne(DealerEarning::class, 'earningable'); + } + + public function isCompleted() + { + return $this->status === DealerPurchaseSubsidyStatus::Completed; + } +} diff --git a/app/Models/DealerPurchaseSubsidyLog.php b/app/Models/DealerPurchaseSubsidyLog.php new file mode 100644 index 00000000..0dddc1a6 --- /dev/null +++ b/app/Models/DealerPurchaseSubsidyLog.php @@ -0,0 +1,15 @@ + \App\Models\DealerManagerSubsidy::class, 'dealer_manage_subsidy' => \App\Models\DealerManageSubsidy::class, 'dealer_channel_subsidy_log' => \App\Models\DealerChannelSubsidyLog::class, + 'dealer_purchase_subsidy' => \App\Models\DealerPurchaseSubsidy::class, ]); JsonResource::withoutWrapping(); diff --git a/database/migrations/2022_01_17_095411_create_dealer_purchase_subsidies_table.php b/database/migrations/2022_01_17_095411_create_dealer_purchase_subsidies_table.php new file mode 100644 index 00000000..407e7ef6 --- /dev/null +++ b/database/migrations/2022_01_17_095411_create_dealer_purchase_subsidies_table.php @@ -0,0 +1,50 @@ +id(); + $table->unsignedBigInteger('user_id')->comment('用户ID'); + $table->unsignedBigInteger('payer_id')->nullable()->comment('付款人ID'); + $table->tinyInteger('lvl')->comment('经销商等级'); + $table->unsignedDecimal('total_purchase_amount', 10, 2)->default(0)->comment('采购总额'); + $table->unsignedDecimal('subsidy_rate', 4, 2)->default(0)->comment('补贴比例(百分比)'); + $table->unsignedDecimal('total_subsidy', 10, 2)->default(0)->comment('补贴总额=采购总额*补贴比例/100'); + $table->unsignedDecimal('total_amount', 10, 2)->default(0)->comment('应得补贴(扣除下级的补贴后的最终金额)'); + $table->unsignedDecimal('real_amount', 10, 2)->default(0)->comment('实得补贴=应得补贴-手续费'); + $table->unsignedDecimal('fee', 10, 2)->default(0)->comment('手续费=应得补贴*手续费率/100'); + $table->unsignedDecimal('fee_rate', 4, 2)->default(0)->comment('手续费率(百分比)'); + $table->timestamp('start_at')->comment('结算开始时间'); + $table->timestamp('end_at')->comment('结算结束时间'); + $table->tinyInteger('settle_state')->default(0)->comment('0=>待处理, 1=>已处理, 2=>已完成'); + $table->tinyInteger('status')->default(0)->comment('状态: 0 待处理'); + $table->string('remark')->nullable()->comment('备注'); + $table->timestamps(); + + $table->unique(['user_id', 'start_at', 'end_at']); + $table->index(['start_at', 'end_at']); + $table->index('status'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('dealer_purchase_subsidies'); + } +} diff --git a/database/migrations/2022_01_17_100317_create_dealer_purchase_subsidy_logs_table.php b/database/migrations/2022_01_17_100317_create_dealer_purchase_subsidy_logs_table.php new file mode 100644 index 00000000..80869592 --- /dev/null +++ b/database/migrations/2022_01_17_100317_create_dealer_purchase_subsidy_logs_table.php @@ -0,0 +1,37 @@ +id(); + $table->unsignedBigInteger('purchase_subsidy_id')->comment('采购补贴ID'); + $table->unsignedBigInteger('change_from_purchase_subsidy_id')->nullable()->comment('变更来源的'); + $table->decimal('change_amount', 10, 2)->comment('变更金额'); + $table->string('remark')->nullable()->comment('备注'); + $table->timestamps(); + + $table->index('purchase_subsidy_id'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('dealer_purchase_subsidy_logs'); + } +}