管理者补贴结算
parent
a419044571
commit
55b8e88919
|
|
@ -0,0 +1,172 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Console\Commands\Dealer;
|
||||||
|
|
||||||
|
use App\Enums\DealerEarningStatus;
|
||||||
|
use App\Enums\DealerEarningType;
|
||||||
|
use App\Models\Dealer;
|
||||||
|
use App\Models\DealerEarning;
|
||||||
|
use Illuminate\Console\Command;
|
||||||
|
use Illuminate\Support\Carbon;
|
||||||
|
use Illuminate\Support\Facades\Cache;
|
||||||
|
use Illuminate\Support\Facades\DB;
|
||||||
|
|
||||||
|
class ManagerSubsidySettleCommand extends Command
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The name and signature of the console command.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $signature = 'dealer:manager-subsidy-settle
|
||||||
|
{--force : 是否强制操作运行}';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The console command description.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $description = '管理者津贴结算';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute the console command.
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function handle()
|
||||||
|
{
|
||||||
|
$tz = now();
|
||||||
|
|
||||||
|
$startAt = $tz->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';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -28,6 +28,14 @@ class Dealer extends Model
|
||||||
'is_manager',
|
'is_manager',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 属于此经销商的管理者津贴
|
||||||
|
*/
|
||||||
|
public function managerSalesLog()
|
||||||
|
{
|
||||||
|
return $this->hasMany(DealerManagerSalesLog::class, 'user_id', 'user_id');
|
||||||
|
}
|
||||||
|
|
||||||
public function getLvlTextAttribute()
|
public function getLvlTextAttribute()
|
||||||
{
|
{
|
||||||
return $this->lvl->text();
|
return $this->lvl->text();
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ namespace App\Models;
|
||||||
|
|
||||||
use App\Enums\DealerEarningStatus;
|
use App\Enums\DealerEarningStatus;
|
||||||
use App\Enums\DealerEarningType;
|
use App\Enums\DealerEarningType;
|
||||||
|
use App\Enums\DealerLvl;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
class DealerEarning extends Model
|
class DealerEarning extends Model
|
||||||
|
|
@ -13,6 +14,8 @@ class DealerEarning extends Model
|
||||||
'end_at' => 'datetime',
|
'end_at' => 'datetime',
|
||||||
'type' => DealerEarningType::class,
|
'type' => DealerEarningType::class,
|
||||||
'status' => DealerEarningStatus::class,
|
'status' => DealerEarningStatus::class,
|
||||||
|
'lvl' => DealerLvl::class,
|
||||||
|
'is_manager' => 'bool',
|
||||||
'completed_at' => 'datetime',
|
'completed_at' => 'datetime',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
@ -24,7 +27,10 @@ class DealerEarning extends Model
|
||||||
'type',
|
'type',
|
||||||
'start_at',
|
'start_at',
|
||||||
'end_at',
|
'end_at',
|
||||||
|
'lvl',
|
||||||
|
'is_manager',
|
||||||
'status',
|
'status',
|
||||||
|
'description',
|
||||||
'completed_at',
|
'completed_at',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
@ -38,4 +44,15 @@ class DealerEarning extends Model
|
||||||
{
|
{
|
||||||
return $query->where('type', DealerEarningType::ManageSubsidy);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,4 +21,12 @@ class DealerManageSubsidyLog extends Model
|
||||||
'total_amount',
|
'total_amount',
|
||||||
'order_completed_at',
|
'order_completed_at',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 此管理津贴所属的经销商
|
||||||
|
*/
|
||||||
|
public function dealer()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Dealer::class, 'user_id', 'user_id');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,4 +23,12 @@ class DealerManagerSalesLog extends Model
|
||||||
'sales_volume',
|
'sales_volume',
|
||||||
'order_completed_at',
|
'order_completed_at',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 此商品销售业绩所属的商品
|
||||||
|
*/
|
||||||
|
public function product()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(DealerProduct::class, 'product_id');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
class AddIsManagerToDealerEarningsTable extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
Schema::table('dealer_earnings', function (Blueprint $table) {
|
||||||
|
$table->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');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
class AddLvlToDealerEarningsTable extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
Schema::table('dealer_earnings', function (Blueprint $table) {
|
||||||
|
$table->tinyInteger('lvl')->comment('经销商等级');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::table('dealer_earnings', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('lvl');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
class AddDescriptionToDealerEarningsTable extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
Schema::table('dealer_earnings', function (Blueprint $table) {
|
||||||
|
$table->text('description')->nullable()->comment('描述');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::table('dealer_earnings', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('description');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue