经销商经结算
parent
17a1b57e77
commit
587fdcf415
|
|
@ -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
|
||||
),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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
|
||||
),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,395 @@
|
|||
<?php
|
||||
|
||||
namespace App\Console\Commands\Dealer;
|
||||
|
||||
use App\Enums\DealerEarningStatus;
|
||||
use App\Enums\DealerLvl;
|
||||
use App\Enums\DealerOrderSettleState;
|
||||
use App\Enums\DealerPurchaseSubsidySettleState;
|
||||
use App\Enums\DealerPurchaseSubsidyStatus;
|
||||
use App\Models\Dealer;
|
||||
use App\Models\DealerOrder;
|
||||
use App\Models\DealerPurchaseLog;
|
||||
use App\Models\DealerPurchaseSubsidy;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class PurchaseSubsidySettleCommand extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'dealer:purchase-subsidy-settle';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = '结算签约经销商的进货补贴';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function handle()
|
||||
{
|
||||
$tz = now();
|
||||
|
||||
$tz = now();
|
||||
|
||||
if ($tz->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';
|
||||
}
|
||||
}
|
||||
|
|
@ -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');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -4,4 +4,5 @@ namespace App\Enums;
|
|||
|
||||
enum DealerManageSubsidyStatus: int {
|
||||
case Pending = 0;
|
||||
case Completed = 5;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,4 +4,5 @@ namespace App\Enums;
|
|||
|
||||
enum DealerManagerSubsidyStatus: int {
|
||||
case Pending = 0;
|
||||
case Completed = 5;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,9 @@
|
|||
<?php
|
||||
|
||||
namespace App\Enums;
|
||||
|
||||
enum DealerPurchaseSubsidySettleState: int {
|
||||
case Pending = 0;
|
||||
case Processed = 1;
|
||||
case Completed = 2;
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
<?php
|
||||
|
||||
namespace App\Enums;
|
||||
|
||||
enum DealerPurchaseSubsidyStatus: int {
|
||||
case Pending = 0;
|
||||
case Completed = 5;
|
||||
}
|
||||
|
|
@ -45,4 +45,14 @@ class DealerManageSubsidy 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 === DealerManageSubsidyStatus::Completed;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否待确认订单
|
||||
*
|
||||
|
|
|
|||
|
|
@ -0,0 +1,63 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use App\Enums\DealerLvl;
|
||||
use App\Enums\DealerPurchaseSubsidySettleState;
|
||||
use App\Enums\DealerPurchaseSubsidyStatus;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class DealerPurchaseSubsidy extends Model
|
||||
{
|
||||
protected $attributes = [
|
||||
'lvl' => 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;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class DealerPurchaseSubsidyLog extends Model
|
||||
{
|
||||
protected $fillable = [
|
||||
'purchase_subsidy_id',
|
||||
'change_from_purchase_subsidy_id',
|
||||
'change_amount',
|
||||
'remark',
|
||||
];
|
||||
}
|
||||
|
|
@ -48,6 +48,7 @@ class AppServiceProvider extends ServiceProvider
|
|||
'dealer_manager_subsidy' => \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();
|
||||
|
|
|
|||
|
|
@ -0,0 +1,50 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class CreateDealerPurchaseSubsidiesTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('dealer_purchase_subsidies', function (Blueprint $table) {
|
||||
$table->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');
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class CreateDealerPurchaseSubsidyLogsTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('dealer_purchase_subsidy_logs', function (Blueprint $table) {
|
||||
$table->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');
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue