优化管理津贴结算
parent
d40df69e03
commit
4f66d94de8
|
|
@ -6,9 +6,9 @@ use App\Enums\DealerLvl;
|
||||||
use App\Enums\DealerManageSubsidyStatus;
|
use App\Enums\DealerManageSubsidyStatus;
|
||||||
use App\Models\Dealer;
|
use App\Models\Dealer;
|
||||||
use App\Models\DealerManageSubsidy;
|
use App\Models\DealerManageSubsidy;
|
||||||
|
use App\Models\DealerManageSubsidyLog;
|
||||||
use Illuminate\Console\Command;
|
use Illuminate\Console\Command;
|
||||||
use Illuminate\Support\Carbon;
|
use Illuminate\Support\Carbon;
|
||||||
use Illuminate\Support\Facades\Cache;
|
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
|
|
||||||
class ManageSubsidySettleCommand extends Command
|
class ManageSubsidySettleCommand extends Command
|
||||||
|
|
@ -18,8 +18,7 @@ class ManageSubsidySettleCommand extends Command
|
||||||
*
|
*
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
protected $signature = 'dealer:manage-subsidy-settle
|
protected $signature = 'dealer:manage-subsidy-settle';
|
||||||
{--force : 是否强制操作运行}';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The console command description.
|
* The console command description.
|
||||||
|
|
@ -42,67 +41,58 @@ class ManageSubsidySettleCommand extends Command
|
||||||
|
|
|
|
||||||
| 管理津贴结算时间为每月的5号和20号。
|
| 管理津贴结算时间为每月的5号和20号。
|
||||||
|
|
|
|
||||||
| 5号结算上月20号0点到当月4号23点59分59秒的管理津贴
|
| 5号结算上月20号0点0分0秒到当月4号23点59分59秒的管理津贴
|
||||||
| 20号结算当月5号0点到19号23点59分59秒的管理津贴
|
| 20号结算当月5号0点0分0秒到19号23点59分59秒的管理津贴
|
||||||
|
|
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
$tz = now();
|
$tz = now();
|
||||||
|
|
||||||
if ($tz->day >= 20) {
|
if ($tz->day >= 20) {
|
||||||
|
// 结算当月5号-19号的管理津贴
|
||||||
$startAt = $tz->copy()->setDay(5)->startOfDay();
|
$startAt = $tz->copy()->setDay(5)->startOfDay();
|
||||||
$endAt = $tz->copy()->setDay(19)->endOfDay();
|
$endAt = $tz->copy()->setDay(19)->endOfDay();
|
||||||
} elseif ($tz->day >= 5) {
|
} elseif ($tz->day >= 5) {
|
||||||
|
// 结算上月20号-到当月4号的管理津贴
|
||||||
$startAt = $tz->copy()->subMonthNoOverflow()->set('day', 20)->startOfDay();
|
$startAt = $tz->copy()->subMonthNoOverflow()->set('day', 20)->startOfDay();
|
||||||
$endAt = $tz->copy()->set('day', 4)->endOfDay();
|
$endAt = $tz->copy()->set('day', 4)->endOfDay();
|
||||||
} else {
|
} else {
|
||||||
|
// 结算上月5号-到19号的管理津贴
|
||||||
$startAt = $tz->copy()->subMonthNoOverflow()->setDay(5)->startOfDay();
|
$startAt = $tz->copy()->subMonthNoOverflow()->setDay(5)->startOfDay();
|
||||||
$endAt = $startAt->copy()->subMonthNoOverflow()->setDay(19)->endOfDay();
|
$endAt = $tz->copy()->subMonthNoOverflow()->setDay(19)->endOfDay();
|
||||||
}
|
}
|
||||||
|
|
||||||
$head = '【'.$startAt->format('Y/m/d').'-'.$endAt->format('Y/m/d').'】';
|
$head = '【'.$startAt->format('Y/m/d').'-'.$endAt->format('Y/m/d').'】';
|
||||||
|
|
||||||
$cacheKey = $this->cacheKey($startAt, $endAt);
|
$this->info("{$head}------------[开始]管理津贴结算------------".PHP_EOL);
|
||||||
|
|
||||||
// 如果不是强制执行,则需检查是否已结算过
|
$this->info("{$head}管理津贴初始化...");
|
||||||
if (! $this->option('force') && Cache::has($cacheKey)) {
|
$this->initializeManageSubsidies($startAt, $endAt, 500);
|
||||||
return $this->warn("{$head}管理津贴已结算");
|
$this->info("{$head}管理津贴初始化完成".PHP_EOL);
|
||||||
}
|
|
||||||
|
|
||||||
$this->info("{$head}------------[开始]管理津贴结算------------");
|
$this->info("{$head}管理津贴结算...");
|
||||||
|
$this->settleManageSubsidies($startAt, $endAt);
|
||||||
if ($this->option('force')) {
|
$this->info("{$head}管理津贴结算完成".PHP_EOL);
|
||||||
$this->info("{$head}正在删除旧数据...");
|
|
||||||
DealerManageSubsidy::where('start_at', $startAt)->where('end_at', $endAt)->delete();
|
|
||||||
$this->info("{$head}数据删除成功");
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->info("{$head}数据写入中...");
|
|
||||||
$this->settle($startAt, $endAt, 500);
|
|
||||||
$this->info("{$head}写入成功, 总耗时: ".$this->formatDuration($tz->diffInMilliseconds(now(), false)));
|
|
||||||
|
|
||||||
|
$this->info("{$head}Done! 总耗时: ".$this->formatDuration($tz->diffInMilliseconds(now(), false)));
|
||||||
$this->info("{$head}------------[结束]管理津贴结算------------".PHP_EOL);
|
$this->info("{$head}------------[结束]管理津贴结算------------".PHP_EOL);
|
||||||
|
|
||||||
Cache::put($cacheKey, 1, $tz->addDays(17));
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 管理津贴结算结算
|
* 初始化管理津贴
|
||||||
*
|
*
|
||||||
* @param \Illuminate\Support\Carbon $startAt
|
* @param \Illuminate\Support\Carbon $startAt
|
||||||
* @param \Illuminate\Support\Carbon $endAt
|
* @param \Illuminate\Support\Carbon $endAt
|
||||||
* @param int $count
|
* @param int $count
|
||||||
* @return void
|
* @return void
|
||||||
*/
|
*/
|
||||||
protected function settle(Carbon $startAt, Carbon $endAt, $count = 200): void
|
protected function initializeManageSubsidies(Carbon $startAt, Carbon $endAt, $count = 200): void
|
||||||
{
|
{
|
||||||
$feeRate = app_settings('dealer.fee_rate');
|
$feeRate = app_settings('dealer.fee_rate');
|
||||||
|
|
||||||
$lastId = Cache::get(
|
$lastId = $this->getLastDealerId($startAt, $endAt);
|
||||||
$cacheKey = $this->cacheKey($startAt, $endAt).':last_id'
|
|
||||||
);
|
|
||||||
|
|
||||||
do {
|
do {
|
||||||
$dealers = Dealer::where('lvl', '>=', DealerLvl::Secondary)
|
$dealers = Dealer::where('lvl', '>=', DealerLvl::Secondary)
|
||||||
|
|
@ -115,67 +105,89 @@ class ManageSubsidySettleCommand extends Command
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
$earnings = [];
|
$manageSubsidies = [];
|
||||||
$tz = now()->toDateTimeString();
|
$tz = now()->toDateTimeString();
|
||||||
|
|
||||||
foreach ($dealers as $dealer) {
|
foreach ($dealers as $dealer) {
|
||||||
[$totalAmount, $remark] = $this->calculateTotalAmount($dealer, $startAt, $endAt);
|
$manageSubsidies[] = [
|
||||||
|
'user_id' => $dealer->user_id,
|
||||||
// 如果 补贴总金额 > 0,则添加管理者补贴记录
|
'total_amount' => 0,
|
||||||
if (bccomp($totalAmount, '0', 2) === 1) {
|
'real_amount' => 0,
|
||||||
// 计算手续费
|
'fee' => 0,
|
||||||
$fee = bcmul($totalAmount, bcdiv($feeRate, '100', 10), 2);
|
'fee_rate' => $feeRate,
|
||||||
|
'start_at' => $startAt,
|
||||||
$earnings[] = [
|
'end_at' => $endAt,
|
||||||
'user_id' => $dealer->user_id,
|
'lvl' => $dealer->lvl,
|
||||||
'total_amount' => $totalAmount,
|
'is_manager' => $dealer->is_manager,
|
||||||
'real_amount' => bcsub($totalAmount, $fee, 2),
|
'status' => DealerManageSubsidyStatus::Pending,
|
||||||
'fee' => $fee,
|
'is_settle' => false,
|
||||||
'fee_rate' => $feeRate,
|
'created_at' => $tz,
|
||||||
'start_at' => $startAt,
|
'updated_at' => $tz,
|
||||||
'end_at' => $endAt,
|
];
|
||||||
'lvl' => $dealer->lvl,
|
|
||||||
'is_manager' => $dealer->is_manager,
|
|
||||||
'status' => DealerManageSubsidyStatus::Pending,
|
|
||||||
'remark' => $remark,
|
|
||||||
'created_at' => $tz,
|
|
||||||
'updated_at' => $tz,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
$lastId = $dealer->id;
|
$lastId = $dealer->id;
|
||||||
}
|
}
|
||||||
|
|
||||||
DealerManageSubsidy::insert($earnings);
|
DealerManageSubsidy::insert($manageSubsidies);
|
||||||
|
|
||||||
Cache::put($cacheKey, $lastId, $endAt);
|
unset($dealers, $manageSubsidies);
|
||||||
|
|
||||||
unset($dealers, $earnings);
|
|
||||||
} while ($dealersCount == $count);
|
} while ($dealersCount == $count);
|
||||||
|
}
|
||||||
|
|
||||||
Cache::forget($cacheKey);
|
/**
|
||||||
|
* 结算管理津贴
|
||||||
|
*
|
||||||
|
* @param \Illuminate\Support\Carbon $startAt
|
||||||
|
* @param \Illuminate\Support\Carbon $endAt
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
protected function settleManageSubsidies(Carbon $startAt, Carbon $endAt)
|
||||||
|
{
|
||||||
|
DealerManageSubsidy::where('start_at', $startAt)->where('end_at', $endAt)->where('is_settle', false)->chunkById(500, function ($subsidies) {
|
||||||
|
foreach ($subsidies as $subsidy) {
|
||||||
|
$this->settleManageSubsidy($subsidy);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 结算单挑管理津贴
|
||||||
|
*
|
||||||
|
* @param \App\Models\DealerManageSubsidy
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
protected function settleManageSubsidy(DealerManageSubsidy $subsidy)
|
||||||
|
{
|
||||||
|
[$totalAmount, $remark] = $this->calculateTotalAmount($subsidy);
|
||||||
|
|
||||||
|
$fee = bcmul($totalAmount, bcdiv($subsidy->fee_rate, '100', 5), 2);
|
||||||
|
|
||||||
|
$subsidy->forceFill([
|
||||||
|
'total_amount' => $totalAmount,
|
||||||
|
'real_amount' => bcsub($totalAmount, $fee, 2),
|
||||||
|
'fee' => $fee,
|
||||||
|
'remark' => $remark,
|
||||||
|
'is_settle' => true,
|
||||||
|
])->save();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 计算补贴总金额
|
* 计算补贴总金额
|
||||||
*
|
*
|
||||||
* @param \App\Models\Dealer
|
* @param \App\Models\DealerManageSubsidy
|
||||||
* @param \Illuminate\Support\Carbon $startAt
|
* @return void
|
||||||
* @param \Illuminate\Support\Carbon $endAt
|
|
||||||
* @return array
|
|
||||||
*/
|
*/
|
||||||
protected function calculateTotalAmount(Dealer $dealer, Carbon $startAt, Carbon $endAt): array
|
protected function calculateTotalAmount(DealerManageSubsidy $subsidy): array
|
||||||
{
|
{
|
||||||
$subsidyLogs = $dealer->manageSubsidyLogs()
|
$subsidyLogs = DealerManageSubsidyLog::select([
|
||||||
->with(['product'])
|
'product_id',
|
||||||
->select([
|
DB::raw('sum(sales_volume) as sales_volume'),
|
||||||
'product_id',
|
DB::raw('sum(total_amount) as total_amount'),
|
||||||
DB::raw('sum(sales_volume) as sales_volume'),
|
])->where(
|
||||||
DB::raw('sum(total_amount) as total_amount'),
|
'user_id', $subsidy->user_id
|
||||||
])
|
)->whereBetween(
|
||||||
->whereBetween('order_completed_at', [$startAt, $endAt])
|
'order_completed_at', [$subsidy->start_at, $subsidy->end_at]
|
||||||
->groupBy('product_id')
|
)->groupBy('product_id')->get();
|
||||||
->get();
|
|
||||||
|
|
||||||
// 补贴总金额
|
// 补贴总金额
|
||||||
$totalAmount = 0;
|
$totalAmount = 0;
|
||||||
|
|
@ -196,15 +208,20 @@ class ManageSubsidySettleCommand extends Command
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 生成缓存的 key
|
* 获取最后
|
||||||
*
|
*
|
||||||
* @param \Illuminate\Support\Carbon $startAt
|
* @param \Illuminate\Support\Carbon $startAt
|
||||||
* @param \Illuminate\Support\Carbon $endAt
|
* @param \Illuminate\Support\Carbon $endAt
|
||||||
* @return void
|
* @return int|null
|
||||||
*/
|
*/
|
||||||
protected function cacheKey(Carbon $startAt, Carbon $endAt)
|
protected function getLastDealerId(Carbon $startAt, Carbon $endAt): ?int
|
||||||
{
|
{
|
||||||
return $startAt->format('Ymd').'_'.$endAt->format('Ymd').'_dealer_manage_subsidy';
|
$lastManageSubsidy = DealerManageSubsidy::where('start_at', $startAt)
|
||||||
|
->where('end_at', $endAt)
|
||||||
|
->latest('id')
|
||||||
|
->first();
|
||||||
|
|
||||||
|
return $lastManageSubsidy?->dealer?->id;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ class DealerManageSubsidy extends Model
|
||||||
protected $attributes = [
|
protected $attributes = [
|
||||||
'lvl' => DealerLvl::None,
|
'lvl' => DealerLvl::None,
|
||||||
'is_manager' => false,
|
'is_manager' => false,
|
||||||
|
'is_settle' => false,
|
||||||
];
|
];
|
||||||
|
|
||||||
protected $casts = [
|
protected $casts = [
|
||||||
|
|
@ -19,6 +20,7 @@ class DealerManageSubsidy extends Model
|
||||||
'start_at' => 'datetime',
|
'start_at' => 'datetime',
|
||||||
'end_at' => 'datetime',
|
'end_at' => 'datetime',
|
||||||
'status' => DealerManageSubsidyStatus::class,
|
'status' => DealerManageSubsidyStatus::class,
|
||||||
|
'is_settle' => 'bool',
|
||||||
];
|
];
|
||||||
|
|
||||||
protected $fillable = [
|
protected $fillable = [
|
||||||
|
|
@ -33,5 +35,14 @@ class DealerManageSubsidy extends Model
|
||||||
'end_at',
|
'end_at',
|
||||||
'status',
|
'status',
|
||||||
'remark',
|
'remark',
|
||||||
|
'is_settle',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 此管理津贴所属的经销商
|
||||||
|
*/
|
||||||
|
public function dealer()
|
||||||
|
{
|
||||||
|
return $this->belongsTo(Dealer::class, 'user_id', 'user_id');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
class AddIsSettleToDealerManageSubsidiesTable extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
Schema::table('dealer_manage_subsidies', function (Blueprint $table) {
|
||||||
|
$table->boolean('is_settle')->default(0)->comment('是否结算');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
Schema::table('dealer_manage_subsidies', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('is_settle');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue