结算订单
parent
ad5ee383ad
commit
4fca777935
|
|
@ -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('%');
|
||||
|
|
|
|||
|
|
@ -0,0 +1,112 @@
|
|||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Models\DistributionPreIncome;
|
||||
use App\Models\Order;
|
||||
use App\Models\UserInfo;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Throwable;
|
||||
|
||||
class OrderSettleCommand extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'order:settle';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = '订单结算';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
// 只查询可结算的订单,并且没有处理中的售后单
|
||||
Order::whereDoesntHave('afterSales', function ($query) {
|
||||
return $query->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,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置申请售后时的录入操作日志
|
||||
*
|
||||
|
|
|
|||
|
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class AgentUpgradeLog extends Model
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = [
|
||||
'user_id',
|
||||
'before_agent_level',
|
||||
'change_agent_level',
|
||||
];
|
||||
}
|
||||
|
|
@ -6,10 +6,21 @@ use Illuminate\Database\Eloquent\Model;
|
|||
|
||||
class DistributionPreIncome extends Model
|
||||
{
|
||||
public const STATUS_PENDING = 0;
|
||||
public const STATUS_PROCESSING = 1;
|
||||
public const STATUS_PROCESSED = 2;
|
||||
|
||||
public const TYPE_PRICE_DIFF = 1;
|
||||
public const TYPE_LEVEL_SAME = 2;
|
||||
public const TYPE_LEVEL_DIFF = 3;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $attributes = [
|
||||
'status' => 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,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 下单人
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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(), '/');
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,62 +0,0 @@
|
|||
<?php
|
||||
|
||||
// 必须包含所有代理等级
|
||||
return [
|
||||
// 会员差价手续费
|
||||
'price_diff_fee_rate' => '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', // 级差奖励
|
||||
],
|
||||
],
|
||||
];
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class CreateAgentUpgradeLogsTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('agent_upgrade_logs', function (Blueprint $table) {
|
||||
$table->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');
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class AddIsSettleToOrdersTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('orders', function (Blueprint $table) {
|
||||
$table->boolean('is_settle')->default(false)->comment('是否结算');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('orders', function (Blueprint $table) {
|
||||
$table->dropColumn(['is_settle']);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -98,6 +98,8 @@ class AppSettingSeeder extends Seeder
|
|||
],
|
||||
'distribution' => [
|
||||
'value' => [
|
||||
// 分销结算时间
|
||||
'settle_days' => '7',
|
||||
// 会员差价手续费
|
||||
'price_diff_fee_rate' => '0.23',
|
||||
// 平级奖励手续费
|
||||
|
|
|
|||
Loading…
Reference in New Issue