6
0
Fork 0
jiqu-library-server/app/Admin/Imports/DealerOrderImport.php

723 lines
25 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<?php
namespace App\Admin\Imports;
use App\Enums\DealerEarningStatus;
use App\Enums\DealerLvl;
use App\Enums\DealerOrderSettleState;
use App\Exceptions\BizException;
use App\Exceptions\ImportException;
use App\Models\Dealer;
use App\Models\DealerChannelSubsidyLog;
use App\Models\DealerManagerSalesLog;
use App\Models\DealerManageSubsidyLog;
use App\Models\DealerOrder;
use App\Models\DealerOrderAllocateLog;
use App\Models\DealerProduct;
use App\Models\DealerPurchaseLog;
use App\Models\DealerUserProduct;
use App\Models\User;
use App\Services\Dealer\OrderService;
use Illuminate\Database\QueryException;
use Illuminate\Support\Facades\DB;
use Throwable;
class DealerOrderImport extends Import
{
public function loadRow($row)
{
/**校验行数据 **/
//获取下单用户
$phone = $row->getCellAtIndex(0)?->getValue();
if (empty($phone)) {
throw new ImportException('未输入下单用户手机号');
}
//获取下单盒数;
$qty = $row->getCellAtIndex(1)?->getValue();
if (empty($qty)) {
throw new ImportException('未输入下单盒数');
}
//获取下单金额;
$totalAmount = $row->getCellAtIndex(2)?->getValue();
if (empty($totalAmount)) {
throw new ImportException('未输入下单金额');
}
//获取目标等级
$toLv = $row->getCellAtIndex(3)?->getValue();
if (empty($toLv)) {
throw new ImportException('未输入目标等级');
}
$productId = $row->getCellAtIndex(4)?->getValue();
if (empty($productId)) {
$productId = 1;
}
$user = User::where('phone', $phone)->first();
dump('手机号:'.$phone.'开始执行');
if ($user) {
$orderService = new OrderService();
$product = DealerProduct::findOrFail($productId);
$shippingAddress = $user->shippingAddresses()->orderBy('is_default', 'desc')->first();
try {
DB::beginTransaction();
//执行自己升级
if ($toLv < 4) {
$user->dealer->upgrade(DealerLvl::from($toLv), '0217后台修改等级');
//执行上级尝试升级
foreach ($user->dealer->getDealers() as $parentDealer) {
$parentDealer->attemptUpgrade();
}
} else {
/**下单 -start **/
//没有地址
if (!$shippingAddress) {
$shippingAddress = $user->shippingAddresses()->create([
'zone_id'=>3,
'zone'=>'北京市 北京市 东城区',
'consignee'=>'测试',
'telephone'=>'18888888888',
'address'=>'1',
'is_default'=>true,
]);
}
$order = $orderService->quickCreateOrder($user, $product, $qty, $shippingAddress->id);
//重新按新规则给一次发货人
if ($order->consignor_id) {
$order->update([
'consignor_id'=>$this->getConsignor($user, $order->total_amount)?->user_id,
]);
$order->refresh();
if (!($order->consignor_id > 1)) {//如果是null或者1
//确认接单
$order = $orderService->confirmOrder($order);
}
}
/**下单 -end **/
dump('下单:'.$order->sn);
/**更新订单状态 -start **/
//【金牌】,【特邀】订单需要发货人有对应的库存,否则往上丢
if (in_array($toLv, [
'2', '3',
])) {
do {
if ($order->consignor_id > 1) {
$userProduct = DealerUserProduct::where('user_id', $order->consignor_id)->where('stock', '>', 0)->first();
if (!$userProduct) {
//没找到库存商品,则继续往上丢
$order = $this->updateOrderConsignor($order);
$order->refresh();
} else {
// if ($userProduct->stock < $qty) {
// //记录手机号
// }
}
} else {
break;
}
} while (!$userProduct);
}
if ($order->isPending()) {
//确认接单
$order = $orderService->confirmOrder($order);
}
//确认打款
$order = $orderService->payOrder($order, 'offline');
//确认收款
$order = $orderService->paidOrder($order);
//如果目标等级是【金牌】【特邀】则只到【待发货】。其余订单走到【已完成】
if (!in_array($toLv, [
'2', '3',
])) {
//确认发货
$order = $orderService->shippingOrder($order);
//确认收货
$order = $orderService->shippingedOrder($order);
}
/**更新订单状态 -end **/
//执行升级结算订单
$this->handleDealerOrder($order);
}
DB::commit();
} catch (QueryException $e) {
DB::rollBack();
if (strpos($e->getMessage(), 'Numeric value out of range') !== false) {
$e = new BizException('当前可发货库存不足');
}
throw $e;
} catch (Throwable $th) {
DB::rollBack();
report($th);
throw new BizException($th->getMessage());
}
} else {
throw new ImportException('未找到用户:'.$phone);
}
}
/**
* 更新订单发货人
*
* @return DealerOrder
*/
public function updateOrderConsignor(DealerOrder $order)
{
//只处理当前订单有发货人的情况
if ($order->consignor) {
$consignor = $this->getConsignor($order->user, $order->total_amount, $order->consignor);
$oldConsignor = $order->consignor;
$order->update([
'allocated_at' => now(),
'consignor_id' => $consignor?->user_id,
]);
//记录分配日志
DealerOrderAllocateLog::create([
'order_id'=>$order->id,
'last_consignor_id'=>$oldConsignor->id,
'new_consignor_id' =>$order->consignor_id,
]);
}
return $order;
}
private function getConsignor(User $user, $totalAmount, ?User $lastConsignor = null)
{
$rules = [
[
'amount' => '2640',
'lvl' => DealerLvl::Contracted,
],
[
'amount' => '860',
'lvl' => DealerLvl::Special,
],
[
'amount' => '630',
'lvl' => DealerLvl::Gold,
],
];
$lvl = $user->dealer->lvl;
//计算通过这个订单可能升级成为的身份
foreach ($rules as $rule) {
if ($totalAmount >= $rule['amount'] && $lvl->value < $rule['lvl']->value) {
$lvl = $rule['lvl'];
}
}
//如果是签约单,直接抛到公司后台发货
if ($lvl->value >= DealerLvl::Contracted->value) {
return null;
}
//新逻辑
$consignor = null;
$_lastConsignor = $lastConsignor;
do {
$query = User::with(['userInfo', 'dealer']);
if ($_lastConsignor) {
$query->where('id', $_lastConsignor->userInfo->real_inviter_id);
} else {
$query->where('id', $user->userInfo->real_inviter_id);
}
$consignor = $query->first();
if ($consignor) {//找到老上级
if ($consignor->dealer->is_sale == true && $consignor->dealer->lvl->value > $lvl->value) {
break;
} else {
$_lastConsignor = $consignor;
$consignor = null;
}
} else {//如果找不到人了
$consignor = $lastConsignor;
break;
}
} while (empty($consignor));
return $consignor?->userInfo;
}
/**
* 处理经销商订单
*
* @param \App\Models\DealerOrder $dealerOrder
* @return void
*/
protected function handleDealerOrder(DealerOrder $dealerOrder)
{
$tz = now()->toDateTimeString();
// 上级经销商
$ancestors = $dealerOrder->dealer->getDealers();
// 签约经销商的进货日志
$this->handlePurchaseLogsOfContractedDealer($dealerOrder, $tz);
// 一级签约经销商和二级经销商的管理津贴
$this->handleManageSubsidyLogs($dealerOrder, $ancestors, $tz);
// 管理者的销售业绩
$this->handleManagerSalesLogs($dealerOrder, $ancestors, $tz);
// 渠道补贴
$this->handleChannelSubsidy($dealerOrder);
if ($dealerOrder->dealer->wasChanged('lvl')) {
$dealers = [
$dealerOrder->dealer,
...$ancestors,
];
foreach ($dealers as $dealer) {
$dealer->attemptUpgrade();
}
}
// 将订单标记为已处理
$dealerOrder->forceFill([
'settle_state' => DealerOrderSettleState::Processed,
])->save();
}
/**
* 计算渠道补贴
*
* @param \App\Models\DealerOrder $dealerOrder
* @return void
*/
protected function handleChannelSubsidy(DealerOrder $dealerOrder)
{
$lvl = $dealerOrder->dealer->lvl;
$lvlValue = [
DealerLvl::Contracted->value => '2640',
DealerLvl::Special->value => '860',
DealerLvl::Gold->value => '630',
];
if ($dealerOrder->total_amount >= $lvlValue[DealerLvl::Contracted->value]) {
// 升级为签约
if ($lvl->value < DealerLvl::Contracted->value) {
$lvl = DealerLvl::Contracted;
}
} elseif ($dealerOrder->total_amount >= $lvlValue[DealerLvl::Special->value]) {
// 升级为特约
if ($lvl->value < DealerLvl::Special->value) {
$lvl = DealerLvl::Special;
}
} elseif ($dealerOrder->total_amount >= $lvlValue[DealerLvl::Gold->value]) {
// 升级为金牌
if ($lvl->value < DealerLvl::Gold->value) {
$lvl = DealerLvl::Gold;
}
}
// 如果经销商等级小于金牌,则没有渠道补贴
if ($lvl->value < DealerLvl::Gold->value) {
return;
}
[$dealers, $rule] = $this->mapDealersAndRuleOfChannel($dealerOrder->dealer, $lvl);
if ($lvl->value >= DealerLvl::Contracted->value) {
$upgradeAmount = $lvlValue[DealerLvl::Contracted->value];
} else {
$upgradeAmount = $lvlValue[$lvl->value];
}
// 手续费比例
$feeRate = app_settings('dealer.fee_rate');
foreach ($dealers as $key => $dealer) {
$ruleKey = $dealer->lvl->value.'_'.$key;
if ($dealer->lvl->value >= DealerLvl::Contracted->value) {
$ruleKey = DealerLvl::Contracted->value.'_'.$key;
}
// 补贴金额
$subsidyAmount = $rule[$ruleKey];
$totalAmount = bcmul($subsidyAmount, $dealerOrder->total_amount, 10);
$totalAmount = bcdiv($totalAmount, $upgradeAmount, 3);
$totalAmount = round($totalAmount, 2);
$channelSubsidyLog = DealerChannelSubsidyLog::create([
'user_id' => $dealer->user_id,
'lvl' => $dealer->lvl,
'order_id' => $dealerOrder->id,
'total_amount' => $totalAmount,
'order_id' => $dealerOrder->id,
'remark' => "补贴总额={$dealerOrder->total_amount}/{$upgradeAmount}*{$subsidyAmount}",
]);
$fee = bcmul($channelSubsidyLog->total_amount, bcdiv($feeRate, '100', 5), 3);
$fee = round($fee, 2);
$channelSubsidyLog->earning()->create([
'user_id' => $channelSubsidyLog->user_id,
'lvl' => $channelSubsidyLog->lvl,
'total_amount' => $channelSubsidyLog->total_amount,
'total_earnings' => bcsub($channelSubsidyLog->total_amount, $fee, 2),
'fee' => $fee,
'fee_rate' => $feeRate,
'payer_id' => $dealerOrder->consignor_id,
'status' => DealerEarningStatus::Pending,
'remark' => "订单号: {$dealerOrder->sn}",
]);
}
$dealerOrder->dealer->upgrade($lvl, '进货升级');
}
/**
* 获取渠道补贴经销商和补贴规则
*
* @param \App\Models\Dealer $dealer
* @param \App\Enums\DealerLvl $lvl
* @return array
*/
protected function mapDealersAndRuleOfChannel(Dealer $dealer, DealerLvl $lvl): array
{
// 渠道补贴经销商
$dealers = [];
// 渠道补贴规则
$rule = null;
// 是否升级
$isUp = $lvl->value > $dealer->lvl->value;
// 最后参与渠道补贴的经销商
$last = null;
// 前一个直属邀请人
$previous = null;
while (true) {
if ($previous) {
$_dealer = $previous->userInfo->realInviterInfo?->dealer;
$_dealer?->setRelation('userInfo', $previous->userInfo->realInviterInfo);
} else {
$_dealer = $dealer->userInfo->realInviterInfo?->dealer;
$_dealer?->setRelation('userInfo', $dealer->userInfo->realInviterInfo);
}
$previous = $_dealer;
if ($_dealer === null) {
break;
}
// 如果经销商等级小于金牌, 那么跳过
if ($_dealer->lvl->value < DealerLvl::Gold->value) {
continue;
}
if ($lvl->value >= DealerLvl::Contracted->value) {
if ($last === null) {
if ($_dealer->lvl->value >= DealerLvl::Contracted->value) {
// 渠道补贴规则: 签约 -> 签约 -> 签约
$rule = [
DealerLvl::Contracted->value.'_0' => '396',
DealerLvl::Contracted->value.'_1' => '79',
];
$dealers[] = $_dealer;
$last = $_dealer;
} elseif ($isUp && $_dealer->isSpecialDealer()) {
// 渠道补贴规则: 签约 -> 特邀 -> 签约 -> 签约
$rule = [
DealerLvl::Special->value.'_0' => '264',
DealerLvl::Contracted->value.'_1' => '132',
DealerLvl::Contracted->value.'_2' => '79',
];
$dealers[] = $_dealer;
$last = $_dealer;
}
} elseif ($_dealer->lvl->value >= DealerLvl::Contracted->value) {
$dealers[] = $_dealer;
// 如果最后参与渠道补贴的经销商是签约, 那么已经找到所有参与渠道补贴的经销商
if ($last->lvl->value >= DealerLvl::Contracted->value) {
break;
}
$last = $_dealer;
}
} elseif ($lvl === DealerLvl::Special) {
if ($_dealer->lvl->value > DealerLvl::Special->value) {
break;
}
if ($last === null) {
if ($_dealer->isSpecialDealer()) {
// 渠道补贴规则: 特邀 -> 特邀 -> 特邀
$rule = [
DealerLvl::Special->value.'_0' => '80',
DealerLvl::Special->value.'_1' => '20',
];
$dealers[] = $_dealer;
$last = $_dealer;
} elseif ($isUp && $_dealer->isGoldDealer()) {
// 渠道补贴规则: 特邀 -> 金牌 -> 特邀 -> 特邀
$rule = [
DealerLvl::Gold->value.'_0' => '50',
DealerLvl::Special->value.'_1' => '30',
DealerLvl::Special->value.'_2' => '20',
];
$dealers[] = $_dealer;
$last = $_dealer;
}
} elseif ($_dealer->isSpecialDealer()) {
$dealers[] = $_dealer;
if ($last->isSpecialDealer()) {
break;
}
$last = $_dealer;
}
} elseif ($lvl === DealerLvl::Gold) {
if ($_dealer->lvl->value >= DealerLvl::Gold->value) {
if ($_dealer->isGoldDealer()) {
// 渠道补贴规则: 金牌 -> 金牌
$rule = [
DealerLvl::Gold->value.'_0' => '75',
];
$dealers[] = $_dealer;
}
break;
}
}
}
return [$dealers, $rule];
}
/**
* 生成签约经销商的进货日志
*
* @param \App\Models\DealerOrder $dealerOrder
* @param array $dealers
* @param string $tz
* @return void
*/
protected function handlePurchaseLogsOfContractedDealer(DealerOrder $dealerOrder, string $tz)
{
if (! $this->isContractedDealerToPurchase($dealerOrder)) {
return;
}
$dealer = $dealerOrder->userInfo->dealer;
// 采购业绩是否算自己的业绩
$valid = $dealer->lvl->value >= DealerLvl::Contracted->value;
$log = new DealerPurchaseLog([
'user_id' => $dealer->user_id,
'lvl' => $dealer->lvl,
'order_id' => $dealerOrder->id,
'total_amount' => $dealerOrder->total_amount,
'path' => $valid ? $dealerOrder->userInfo->full_path : $dealerOrder->userInfo->path,
'remark' => $valid ? null : '升级签约',
]);
$log->setCreatedAt($tz);
$log->setUpdatedAt($tz);
$log->save();
}
/**
* 分配一级签约经销商和二级经销商的管理津贴
*
* @param \App\Models\DealerOrder $dealerOrder
* @param array $dealers
* @param string $tz
* @return void
*/
protected function handleManageSubsidyLogs(DealerOrder $dealerOrder, array $dealers, string $tz)
{
if (! $this->isContractedDealerToPurchase($dealerOrder)) {
return;
}
$logs = [];
foreach ($dealerOrder->products as $product) {
if ($product->productManageSubsidyRules->isEmpty()) {
continue;
}
// 管理津贴分配规则
$rules = $product->productManageSubsidyRules->keyBy('lvl');
$last = null;
$ranking = 0;
foreach ($dealers as $dealer) {
if (! in_array($dealer->lvl, [DealerLvl::Secondary, DealerLvl::Top])) {
continue;
}
// 如果当前经销商等级没有对应的管理津贴分配规则,则忽略
if (is_null($rule = $rules->get($dealer->lvl->value))) {
continue;
}
// 同等级管理津贴最多给三次
if ($last === null || $dealer->lvl->value > $last->lvl->value) {
if ($ranking < 3 && $dealer->lvl === DealerLvl::Top) {
if ($secondarySubsidyRule = $rules->get(DealerLvl::Secondary->value)) {
$key = 'price_'.(1 + $ranking).'st';
$secondarySubsidy = $secondarySubsidyRule->{$key};
if (bccomp($secondarySubsidy, '0') === 1) {
$logs[] = [
'user_id' => $dealer->user_id,
'order_id' => $product->order_id,
'product_id' => $product->product_id,
'lvl' => $dealer->lvl,
'sales_volume' => $product->qty,
'total_amount' => bcmul($product->qty, $secondarySubsidy, 2),
'created_at' => $tz,
'updated_at' => $tz,
];
}
}
}
$ranking = 1;
} elseif ($ranking < 3 && $dealer->lvl->value === $last->lvl->value) {
$ranking++;
} else {
continue;
}
$subsidy = $rule->{"price_{$ranking}st"};
if (bccomp($subsidy, '0') === 1) {
$logs[] = [
'user_id' => $dealer->user_id,
'order_id' => $product->order_id,
'product_id' => $product->product_id,
'lvl' => $dealer->lvl,
'sales_volume' => $product->qty,
'total_amount' => bcmul($product->qty, $subsidy, 2),
'created_at' => $tz,
'updated_at' => $tz,
];
}
$last = $dealer;
}
}
DealerManageSubsidyLog::insert($logs);
}
/**
* 过滤出可能会享受管理津贴的经销商每个等级最多3人
*
* @param array $dealers
* @return array
*/
protected function mapManageSubsidyDealers(array $dealers): array
{
$map = [];
$last = null;
$ranking = 1;
foreach ($dealers as $dealer) {
if ($last === null || $dealer->lvl->value > $last->lvl->value) {
$last = $dealer;
$map[] = $last;
$ranking = 1;
} elseif ($ranking < 3 && $dealer->lvl->value === $last->lvl->value) {
$last = $dealer;
$map[] = $last;
$ranking++;
}
}
return $map;
}
/**
* 生成管理者的销售业绩
*
* @param \App\Models\DealerOrder $dealerOrder
* @param array $dealers
* @param string $tz
* @return void
*/
protected function handleManagerSalesLogs(DealerOrder $dealerOrder, array $dealers, string $tz): void
{
if (! $this->isContractedDealerToPurchase($dealerOrder)) {
return;
}
if (is_null($manager = $this->firstManager($dealers))) {
return;
}
$logs = [];
foreach ($dealerOrder->products as $product) {
$logs[] = [
'user_id' => $manager->user_id,
'lvl' => $manager->lvl,
'order_id' => $product->order_id,
'product_id' => $product->product_id,
'sales_volume' => $product->qty,
'created_at' => $tz,
'updated_at' => $tz,
];
}
DealerManagerSalesLog::insert($logs);
}
/**
* 从给定的经销商中获取第一个管理者
*
* @param array $dealers
* @return \App\Models\Dealer|null
*/
protected function firstManager(array $dealers): ?Dealer
{
foreach ($dealers as $dealer) {
if ($dealer->is_manager) {
return $dealer;
}
}
return null;
}
/**
* 确认是否是签约经销商进货
*
* @param DealerOrder $dealerOrder
* @return bool
*/
protected function isContractedDealerToPurchase(DealerOrder $dealerOrder): bool
{
$dealer = $dealerOrder->userInfo->dealer;
if ($dealer->lvl->value < DealerLvl::Contracted->value) {
if ($dealerOrder->total_amount < '2640') {
return false;
}
}
return true;
}
}