From 4fca7779352cee7ff9a22ab4c6a125573681267d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E9=9D=99?= Date: Wed, 29 Dec 2021 19:34:25 +0800 Subject: [PATCH] =?UTF-8?q?=E7=BB=93=E7=AE=97=E8=AE=A2=E5=8D=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/Admin/Forms/Settings/Distribution.php | 1 + app/Console/Commands/OrderSettleCommand.php | 112 +++++++++++ .../Controllers/Account/WalletController.php | 2 +- app/Models/AfterSale.php | 27 +++ app/Models/AgentUpgradeLog.php | 17 ++ app/Models/DistributionPreIncome.php | 30 ++- app/Models/Order.php | 14 ++ app/Models/UserInfo.php | 186 +++++++++++++++++- config/distribution.php | 62 ------ ...171630_create_agent_upgrade_logs_table.php | 34 ++++ ...9_184438_add_is_settle_to_orders_table.php | 32 +++ database/seeders/AppSettingSeeder.php | 2 + 12 files changed, 451 insertions(+), 68 deletions(-) create mode 100644 app/Console/Commands/OrderSettleCommand.php create mode 100644 app/Models/AgentUpgradeLog.php delete mode 100644 config/distribution.php create mode 100644 database/migrations/2021_12_29_171630_create_agent_upgrade_logs_table.php create mode 100644 database/migrations/2021_12_29_184438_add_is_settle_to_orders_table.php diff --git a/app/Admin/Forms/Settings/Distribution.php b/app/Admin/Forms/Settings/Distribution.php index 45527691..383cadf5 100644 --- a/app/Admin/Forms/Settings/Distribution.php +++ b/app/Admin/Forms/Settings/Distribution.php @@ -39,6 +39,7 @@ class Distribution extends Form // dd(config('distribution'), app_settings('distribution')); + $this->number('settle_days', '订单结算时间(天)')->value($appSettings['settle_days'] ?? 0)->help('订单完成后,隔多少天可以结算'); $this->currency('price_diff_fee_rate', '会员差价手续费')->value($appSettings['price_diff_fee_rate'] ?? 0)->symbol('%'); $this->currency('lvl_same_bonus_fee_rate', '平级奖励手续费')->value($appSettings['lvl_same_bonus_fee_rate'] ?? 0)->symbol('%'); $this->currency('lvl_diff_bonus_fee_rate', '级差奖励手续费')->value($appSettings['lvl_diff_bonus_fee_rate'] ?? 0)->symbol('%'); diff --git a/app/Console/Commands/OrderSettleCommand.php b/app/Console/Commands/OrderSettleCommand.php new file mode 100644 index 00000000..d2ebb4f0 --- /dev/null +++ b/app/Console/Commands/OrderSettleCommand.php @@ -0,0 +1,112 @@ +processing(); + })->settlable()->chunkById(200, function ($orders) { + $orders->load(['user', 'afterSales']); + + foreach ($orders as $order) { + try { + DB::beginTransaction(); + + $this->settle($order); + + DB::commit(); + } catch (Throwable $e) { + DB::rollBack(); + + report($e); + } + } + }); + + return 0; + } + + /** + * 结算成长值 + * + * @param \App\Models\Order $order + * @return void + */ + protected function settle(Order $order) + { + // 用户可得销售值 + $salesValue = $order->sales_value; + + foreach ($order->afterSales as $afterSale) { + if ($afterSale->isCancelled()) { + continue; + } + + $salesValue = bcsub($salesValue, $afterSale->sales_value, 2); + } + + $user = $order->user; + + // 结算下单用户的成长值 + $user->userInfo()->update([ + 'growth_value' => DB::raw("growth_value+{$salesValue}"), + 'pre_growth_value' => DB::raw("pre_growth_value-{$salesValue}"), + ]); + + // 尝试提升用户的代理等级 + $user->userInfo->attemptUpgradeAgentLevel(); + + if (count($pids = $user->userInfo->parent_ids) > 0) { + // 更新上级的团队销售值 + UserInfo::whereIn('user_id', $pids)->update([ + 'group_sales_value' => DB::raw("group_sales_value + {$salesValue}"), + ]); + + $ancestors = UserInfo::whereIn('user_id', $pids)->latest('depth')->get(); + + foreach ($ancestors as $ancestor) { + $ancestor->attemptUpgradeAgentLevel(); + } + } + + // 将订单标记未已结算 + $order->update([ + 'is_settle' => true, + ]); + + // 将预收益标记为结算中 + DistributionPreIncome::where('order_id', $order->id)->update([ + 'status' => DistributionPreIncome::STATUS_PROCESSING, + ]); + } +} diff --git a/app/Endpoint/Api/Http/Controllers/Account/WalletController.php b/app/Endpoint/Api/Http/Controllers/Account/WalletController.php index aa0b5507..38581b08 100644 --- a/app/Endpoint/Api/Http/Controllers/Account/WalletController.php +++ b/app/Endpoint/Api/Http/Controllers/Account/WalletController.php @@ -57,7 +57,7 @@ class WalletController extends Controller $perPage = PaginatorHelper::resolvePerPage('per_page', 20, 50); $distributionLogs = $request->user()->distributionPreIncomes() ->with('logs') - ->pending() + ->unsettlement() ->latest('id') ->simplePaginate($perPage); diff --git a/app/Models/AfterSale.php b/app/Models/AfterSale.php index 35f16ac3..a6da4b25 100644 --- a/app/Models/AfterSale.php +++ b/app/Models/AfterSale.php @@ -66,6 +66,23 @@ class AfterSale extends Model return $afterSaleState; } + /** + * 仅查询处理中的售后订单 + * + * @param \Illuminate\Database\Eloquent\Builder $query + * @return \Illuminate\Database\Eloquent\Builder + */ + public function scopeProcessing($query) + { + return $query->whereIn('state', [ + static::STATE_APPLY, + static::STATE_VERIFY, + static::STATE_AGREE, + static::STATE_SHIPPING, + static::STATE_FINANCE, + ]); + } + public function user() { return $this->belongsTo(User::class, 'user_id'); @@ -101,6 +118,16 @@ class AfterSale extends Model return $this->type === static::TYPE_CHANGE; } + /** + * 确认此售后单是否已取消 + * + * @return bool + */ + public function isCancelled(): bool + { + return $this->status === static::STATE_CANCEL; + } + /** * 设置申请售后时的录入操作日志 * diff --git a/app/Models/AgentUpgradeLog.php b/app/Models/AgentUpgradeLog.php new file mode 100644 index 00000000..ea76a47c --- /dev/null +++ b/app/Models/AgentUpgradeLog.php @@ -0,0 +1,17 @@ + self::STATUS_PENDING, + ]; + /** * @var array */ @@ -43,12 +54,23 @@ class DistributionPreIncome extends Model ]; /** - * 待结算预收益 - * + * @var array */ - public function scopePending($query) + public static $statusTexts = [ + self::STATUS_PENDING => '待结算', + self::STATUS_PROCESSING => '结算中', + self::STATUS_PROCESSED => '已结算', + ]; + + /** + * 仅查询未结算的预收益 + */ + public function scopeUnsettlement($query) { - return $query->where('status', '=', 0); + return $query->whereIn('status', [ + static::STATUS_PENDING, + static::STATUS_PROCESSING, + ]); } /** diff --git a/app/Models/Order.php b/app/Models/Order.php index d174d27e..ede20560 100644 --- a/app/Models/Order.php +++ b/app/Models/Order.php @@ -41,6 +41,8 @@ class Order extends Model */ protected $attributes = [ 'reduced_amount' => 0, + 'is_settle' => false, + 'is_change' => false, 'status' => self::STATUS_PENDING, ]; @@ -52,6 +54,7 @@ class Order extends Model 'completed_at' => 'datetime', 'auto_complete_at' => 'datetime', 'status' => 'int', + 'is_settle' => 'bool', 'is_change' => 'bool', ]; @@ -83,6 +86,7 @@ class Order extends Model 'completed_at', 'auto_complete_at', 'is_change', + 'is_settle', ]; /** @@ -104,6 +108,16 @@ class Order extends Model ->where('auto_complete_at', '<=', now()); } + /** + * 仅查询可结算的订单 + */ + public function scopeSettlable() + { + return $this->where('status', static::STATUS_COMPLETED) + ->where('completed_at', '<=', now()->subDays(app_settings('distribution.settle_days', 7))) + ->where('is_settle', false); + } + /** * 下单人 * diff --git a/app/Models/UserInfo.php b/app/Models/UserInfo.php index 5efa3f50..681e78eb 100644 --- a/app/Models/UserInfo.php +++ b/app/Models/UserInfo.php @@ -2,8 +2,8 @@ namespace App\Models; -use App\Helpers\Str; use Illuminate\Database\Eloquent\Model; +use Illuminate\Support\Str; class UserInfo extends Model { @@ -157,6 +157,180 @@ class UserInfo extends Model return $this->hasMany(DistributionPreIncome::class, 'user_id', 'user_id'); } + /** + * 获取此用户的代理升级日志 + */ + public function agentUpgradeLogs() + { + return $this->hasMany(AgentUpgradeLog::class, 'user_id', 'user_id'); + } + + /** + * 获取此用户的直推店铺总数 + */ + public function getVipAgentsCount() + { + return static::where('inviter_id', $this->getKey()) + ->where('agent_level', '>=', static::AGENT_LEVEL_VIP) + ->count(); + } + + /** + * 获取此用户的不同线上的下级区级代理总数 + */ + public function getDistrictAgentsCountOnDifferentLines() + { + $path = $this->full_path; + + // 获取所有区级以上的代理 + $agents = static::where('agent_level', '>=', static::AGENT_LEVEL_DISTRICT) + ->where('path', 'like', "{$path}%") + ->get(); + + $lines = []; + + foreach ($agents as $agent) { + preg_match("#\A{$path}\d+/#", $agent->full_path, $matches); + + $line = $matches[0]; + + if (! isset($lines[$line])) { + $lines[$line] = 1; + } + } + + return count($lines); + } + + /** + * 获取此用户的不同线上的下级市级代理总数 + */ + public function getCityAgentsCountOnDifferentLines() + { + $path = $this->full_path; + + // 获取所有市级以上的代理 + $agents = static::where('agent_level', '>=', static::AGENT_LEVEL_CITY) + ->where('path', 'like', "$path%") + ->get(); + + $lines = []; + + foreach ($agents as $agent) { + preg_match("#\A{$path}\d+/#", $agent->full_path, $matches); + + $line = $matches[0]; + + if (! isset($lines[$line])) { + $lines[$line] = 1; + } + } + + return count($lines); + } + + /** + * 获取此用户的不同线上的下级省级代理总数 + */ + public function getProvinceAgentsCountOnDifferentLines() + { + $path = $this->full_path; + + // 获取所有省级以上的代理 + $agents = static::where('agent_level', '>=', static::AGENT_LEVEL_PROVINCE) + ->where('path', 'like', "$path%") + ->get(); + + $lines = []; + + foreach ($agents as $agent) { + preg_match("#\A{$path}\d+/#", $agent->full_path, $matches); + + $line = $matches[0]; + + if (! isset($lines[$line])) { + $lines[$line] = 1; + } + } + + return count($lines); + } + + /** + * 尝试提升代理等级 + * + * @return void + */ + public function attemptUpgradeAgentLevel(): void + { + $lvl = $this->agent_level; + + // 如果代理等级是分公司或董事时,不能继续提升代理等级 + if (in_array($lvl, [static::AGENT_LEVEL_BRANCH, static::AGENT_LEVEL_DIRECTOR])) { + return; + } + + // 如果成长值不足650时,不能升级 + if (bccomp($this->group_sales_value, '650') < 0) { + return; + } + + // 如果代理等级是粉丝,则可升级为店铺 + if ($lvl === static::AGENT_LEVEL_CIVILIAN) { + $lvl = static::AGENT_LEVEL_VIP; + } + + // 总团队销售值 = 团队销售值 + 个人成长值 + $salesValue = bcadd($this->group_sales_value, $this->growth_value, 2); + + if ($lvl === static::AGENT_LEVEL_VIP) { + $vipsCount = $this->getVipAgentsCount(); + + // 如果直推店铺人数>=6,并且团队销售值>=65000,则可升级为区级代理 + // 或者直推店铺人数>=4,则可升级为社区 + if ($vipsCount >= 6 && bccomp($salesValue, '65000') >= 0) { + $lvl = static::AGENT_LEVEL_DISTRICT; + } elseif ($vipsCount >= 4) { + $lvl = static::AGENT_LEVEL_COMMUNITY; + } + } elseif ($lvl === static::AGENT_LEVEL_COMMUNITY && bccomp($salesValue, '65000') >= 0) { + if ($this->getVipAgentsCount() >= 6) { + $lvl = static::AGENT_LEVEL_DISTRICT; + } + } + + if ($lvl === static::AGENT_LEVEL_DISTRICT && bccomp($salesValue, '780000') >= 0) { + if ($this->getDistrictAgentsCountOnDifferentLines() >= 3) { + $lvl = static::AGENT_LEVEL_CITY; + } + } + + if ($lvl === static::AGENT_LEVEL_CITY && bccomp($salesValue, '7800000') >= 0) { + if ($this->getCityAgentsCountOnDifferentLines() >= 2) { + $lvl = static::AGENT_LEVEL_PROVINCE; + } + } + + if ($lvl === static::AGENT_LEVEL_PROVINCE && bccomp($salesValue, '52000000') >= 0) { + if ($this->getProvinceAgentsCountOnDifferentLines() >= 2) { + $lvl = static::AGENT_LEVEL_BRANCH; + } + } + + if ($this->agent_level !== $lvl) { + $beforeAgentLevel = $this->agent_level; + + $this->update([ + 'agent_level' => $lvl, + ]); + + $this->agentUpgradeLogs()->create([ + 'before_agent_level' => $beforeAgentLevel, + 'change_agent_level' => $lvl, + ]); + } + } + /** * 变更预收益成长值 * @@ -223,4 +397,14 @@ class UserInfo extends Model { return static::$agentLevelTexts[$this->agent_level] ?? '未知'; } + + /** + * 获取完整的邀请路径 + * + * @return string + */ + public function getFullPathAttribute(): string + { + return Str::finish($this->path.$this->getKey(), '/'); + } } diff --git a/config/distribution.php b/config/distribution.php deleted file mode 100644 index 0c4e5cdc..00000000 --- a/config/distribution.php +++ /dev/null @@ -1,62 +0,0 @@ - '0.23', - // 平级奖励手续费 - 'lvl_same_bonus_fee_rate' => '0', - // 级差奖励手续费 - 'lvl_diff_bonus_fee_rate' => '0.10', - - // 代理等级分润规则 - 'rules' => [ - // 平民(粉丝) - 'civilian' => [ - 'lvl_same_bonus_rate' => '0', // 平级奖励比例 - 'lvl_diff_bonus_rate' => '0', // 级差奖励比例 - ], - - // 店铺 - 'vip' => [ - 'lvl_same_bonus_rate' => '0', // 平级奖励比例 - 'lvl_diff_bonus_rate' => '0.02', // 级差奖励比例 - ], - - // 社区 - 'community' => [ - 'lvl_same_bonus_rate' => '0.01', // 平级奖励比例 - 'lvl_diff_bonus_rate' => '0.10', // 级差奖励比例 - ], - - // 区级 - 'district' => [ - 'lvl_same_bonus_rate' => '0.02', // 平级奖励比例 - 'lvl_diff_bonus_rate' => '0.19', // 级差奖励比例 - ], - - // 市级 - 'city' => [ - 'lvl_same_bonus_rate' => '0.01', // 平级奖励比例 - 'lvl_diff_bonus_rate' => '0.32', // 级差奖励比例 - ], - - // 省级 - 'province' => [ - 'lvl_same_bonus_rate' => '0.01', // 平级奖励比例 - 'lvl_diff_bonus_rate' => '0.42', // 级差奖励比例 - ], - - // 分公司 - 'branch' => [ - 'lvl_same_bonus_rate' => '0.01', // 平级奖励比例 - 'lvl_diff_bonus_rate' => '0.48', // 级差奖励比例 - ], - - // 董事 - 'director' => [ - 'lvl_same_bonus_rate' => '0.01', // 平级奖励比例 - 'lvl_diff_bonus_rate' => '0.50', // 级差奖励 - ], - ], -]; diff --git a/database/migrations/2021_12_29_171630_create_agent_upgrade_logs_table.php b/database/migrations/2021_12_29_171630_create_agent_upgrade_logs_table.php new file mode 100644 index 00000000..0033d55b --- /dev/null +++ b/database/migrations/2021_12_29_171630_create_agent_upgrade_logs_table.php @@ -0,0 +1,34 @@ +id(); + $table->unsignedBigInteger('user_id'); + $table->tinyInteger('before_agent_level')->comment('变更前的代理等级'); + $table->tinyInteger('change_agent_level')->comment('变更的代理等级'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('agent_upgrade_logs'); + } +} diff --git a/database/migrations/2021_12_29_184438_add_is_settle_to_orders_table.php b/database/migrations/2021_12_29_184438_add_is_settle_to_orders_table.php new file mode 100644 index 00000000..cf8048de --- /dev/null +++ b/database/migrations/2021_12_29_184438_add_is_settle_to_orders_table.php @@ -0,0 +1,32 @@ +boolean('is_settle')->default(false)->comment('是否结算'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('orders', function (Blueprint $table) { + $table->dropColumn(['is_settle']); + }); + } +} diff --git a/database/seeders/AppSettingSeeder.php b/database/seeders/AppSettingSeeder.php index 230b9d44..4ead3795 100644 --- a/database/seeders/AppSettingSeeder.php +++ b/database/seeders/AppSettingSeeder.php @@ -98,6 +98,8 @@ class AppSettingSeeder extends Seeder ], 'distribution' => [ 'value' => [ + // 分销结算时间 + 'settle_days' => '7', // 会员差价手续费 'price_diff_fee_rate' => '0.23', // 平级奖励手续费