vd/app/Domains/Virtual/Services/FlowPoolService.php
2019-02-20 15:49:15 +08:00

389 lines
14 KiB
PHP

<?php
namespace App\Domains\Virtual\Services;
use App\Dicts;
use Carbon\Carbon;
use App\Core\Service;
use Illuminate\Validation\Rule;
use App\Models\Virtual\FlowPool;
use App\Models\Virtual\OrderCard;
use Illuminate\Support\Facades\DB;
use App\Exceptions\NotExistException;
use App\Exceptions\NotAllowedException;
use App\Models\Virtual\FlowPoolSetting;
use Illuminate\Support\Facades\Validator;
use App\Domains\Virtual\Services\CompanyService;
use App\Domains\Virtual\Services\PackageService;
use App\Domains\Virtual\Repositories\FlowPoolRepository;
use App\Domains\Virtual\Repositories\OrderCardRepository;
use App\Domains\Virtual\Repositories\FlowPoolCardRepository;
use App\Domains\Virtual\Repositories\FlowPoolMonthRepository;
use App\Domains\Virtual\Repositories\FlowPoolSettingRepository;
use App\Domains\Real\Repositories\FlowPoolRepository as RealFlowPoolRepository;
use App\Exceptions\InvalidArgumentException;
use function App\range_compare;
class FlowPoolService extends Service
{
protected $realFlowPoolRepository;
protected $flowPoolRepository;
protected $flowPoolPackageRepository;
protected $flowPoolSettingRepository;
protected $flowPoolCardRepository;
protected $flowPoolMonthRepository;
protected $pools;
/**
* 构造函数
*
* @return void
*/
public function __construct(
RealFlowPoolRepository $realFlowPoolRepository,
FlowPoolRepository $flowPoolRepository,
FlowPoolSettingRepository $flowPoolSettingRepository,
FlowPoolCardRepository $flowPoolCardRepository,
FlowPoolMonthRepository $flowPoolMonthRepository
) {
$this->realFlowPoolRepository = $realFlowPoolRepository;
$this->flowPoolRepository = $flowPoolRepository;
$this->flowPoolSettingRepository = $flowPoolSettingRepository;
$this->flowPoolCardRepository = $flowPoolCardRepository;
$this->flowPoolMonthRepository = $flowPoolMonthRepository;
}
/**
* RD流量池列表
*
* @return void
*/
public function real()
{
$used = $this->flowPoolRepository->select(['id', 'real_pool_ids'])->get();
$array = [];
foreach ($used as $item) {
$item['real_pool_ids'] = $item['real_pool_ids'] ?? [];
foreach ($item['real_pool_ids'] as $key => $value) {
$array[$value] = $item['id'];
}
}
$list = $this->realFlowPoolRepository->get();
$list->map(function ($item) use ($array) {
$item->virtual_pool_id = $array[$item['id']] ?? 0;
});
return $list;
}
/**
* 流量池列表
*
* @param array $conditions
* @return mixed
*/
public function index(array $conditions = [])
{
$limit = $conditions['limit'] ?? 20;
$flowPools = $this->flowPoolRepository->withConditions($conditions)
->applyConditions()->paginate($limit);
$packages = $this->flowPoolCardRepository->select([
'pool_id',
'package_id',
])->withConditions(['pool_id' => $flowPools->pluck('id')->toArray()])->groupBy(['pool_id', 'package_id'])->get();
$packages->map(function ($item) {
$item->package_name = app(PackageService::class)->load($item->package_id)['name'];
});
$packages = $packages->groupBy('pool_id');
$settings = $this->flowPoolSettingRepository->withConditions(['pool_id' => $flowPools->pluck('id')->toArray()])->orderBy('start_at', 'desc')->get();
$settings->map(function ($item) use ($packages) {
$itemPackages = $packages[$item->pool_id] ?? [];
$minimum_settings = $item->minimum_settings ?? [];
foreach ($itemPackages as $package) {
if (!in_array($package['package_id'], array_pluck($minimum_settings, 'package_id'))) {
$minimum_settings[] = [
'package_id' => $package['package_id'],
'package_name' => $package['package_name'],
'flows' => 0,
'price' => 0
];
}
}
$item->minimum_settings = $minimum_settings;
});
$settings = $settings->groupBy('pool_id');
$carrierOperators = app(Dicts::class)->get('carrier_operator');
$shares = app(Dicts::class)->get('shares');
$flowPools->map(function ($item) use ($carrierOperators, $shares, $packages, $settings) {
$item->company_name = app(CompanyService::class)->load($item['company_id'])['name'];
$item->carrier_operator_name = $carrierOperators[$item['carrier_operator']];
$item->shared_name = $shares[$item['shared']];
$item->real_pool_ids = empty($item->real_pool_ids) ? [] : $item->real_pool_ids;
$item->status = $item->end_at ? 1 : 0;
$item->packages = $packages[$item->id] ?? [];
$item->settings = $settings[$item->id] ?? [];
});
return $flowPools;
}
/**
* 存储流量池
*
* @param array $attributes
* @return FlowPool
*/
public function store(array $attributes = [])
{
$attributes['start_at'] = $attributes['start_at'] ? Carbon::parse($attributes['start_at'])->startOfMonth()->format('Y-m-d H:i:s') : Carbon::now()->startOfMonth()->format('Y-m-d H:i:s');
$attributes['end_at'] = $attributes['status'] ? Carbon::now()->endOfMonth()->format('Y-m-d H:i:s') : null;
$attributes = array_only($attributes, ['id', 'company_id', 'name', 'flows', 'carrier_operator', 'shared', 'real_pool_ids', 'remark', 'start_at', 'end_at']);
$rule = [
'name' => ['required', 'between:2,32', Rule::unique($this->flowPoolRepository->getTable(), 'name')->ignore($attributes['id'])->whereNUll('deleted_at')],
'carrier_operator' => ['required', 'in:0,1,2,3'],
'shared' => ['required', 'in:1,2'],
];
$message = [
'name.required' => '请输入流量池名称',
'name.between' => '流量池名称长度不合法',
'name.unique' => '流量池名称已经被其他用户所使用',
'carrier_operator.required' => '请选择运营商',
'carrier_operator.in' => '运营商不合法',
'shared.required' => '请选择共享类型',
'shared.in' => '共享类型不合法',
];
Validator::validate($attributes, $rule, $message);
if (!$attributes['id']) {
$maxId = FlowPool::withTrashed()->max('id');
$attributes['id'] = $maxId ? $maxId + 1 : 1;
$attributes['sn'] = self::sn($attributes['id']);
$node = $this->flowPoolRepository->create($attributes);
}
if ($attributes['id']) {
$node = $this->flowPoolRepository->find($attributes['id']);
if (!$node) {
throw new NotExistException('流量池不存在或已删除');
}
$this->flowPoolRepository->setModel($node)->update($attributes);
}
return $node;
}
/**
* 删除
*
* @return bool
*/
public function destroy($ids)
{
$ids = is_array($ids) ? $ids : [$ids];
$this->flowPoolRepository->destroy($ids);
return true;
}
/**
* 添加卡
*
* @return void
*/
public function addCards($poolId, array $simArray)
{
if (!$this->flowPoolRepository->find($poolId)) {
throw new NotExistException('流量池不存在或已删除');
}
DB::transaction(function () use ($poolId, $simArray) {
foreach (array_chunk($simArray, 20000) as $chunk) {
$array = app(OrderCardRepository::class)->select(['sim', 'package_id'])->withConditions(['sim' => $chunk])
->get()->pluck('package_id', 'sim')->toArray();
$data = [];
foreach ($chunk as $key => $value) {
if (!isset($array[$value])) {
throw new NotAllowedException("{$value} 不存在销售记录");
}
$data[] = [
'pool_id' => $poolId,
'sim' => $value,
'package_id' => $array[$value],
];
}
$this->flowPoolCardRepository->upsert($data, 'sim');
}
});
$this->flowPoolCardRepository->forgetCached();
return true;
}
/**
* 定价管理
*
* @param array $attributes
* @return FlowPool
*/
public function setting(array $attributes = [])
{
$attributes['start_at'] = Carbon::parse($attributes['start_at'])->startOfMonth()->format('Y-m-d H:i:s');
$attributes['end_at'] = Carbon::parse($attributes['end_at'])->endOfMonth()->format('Y-m-d H:i:s');
if ($attributes['start_at'] > $attributes['end_at']) {
throw new InvalidArgumentException('开始时间必须小于结束时间');
}
$rule = [
'pool_id' => ['required', Rule::exists($this->flowPoolRepository->getTable(), 'id')],
'first_month_price' => ['required', 'integer'],
'other_month_price' => ['required', 'integer'],
'gradient' => ['required', 'integer'],
'gradient_unit' => ['required', 'in:0,1'],
];
$message = [
'pool_id.required' => '请输入流量池ID',
'first_month_price.required' => '请输入首月单价',
'other_month_price.required' => '请输入次月单价',
'gradient.required' => '请输入梯度',
'gradient_unit.required' => '请选择梯度单位',
];
Validator::validate($attributes, $rule, $message);
if (!$attributes['id']) {
DB::transaction(function () use ($attributes) {
$settings = $this->flowPoolSettingRepository->withConditions(['pool_id' => $attributes['pool_id']])->get();
if (empty($settings)) {
$attributes['start_at'] = '2000-01-01 00:00:00';
$attributes['end_at'] !== '3000-01-01 23:59:59';
}
$creates = [];
if (!empty($settings)) {
foreach ($settings as $item) {
$result = range_compare([$attributes['start_at'], $attributes['end_at']], [$item['start_at'], $item['end_at']]);
switch ($result) {
case 0:
$this->flowPoolSettingRepository->where(['id' => $item['id']])->update($attributes);
$creates = [];
break 2;
case 1:
$this->flowPoolSettingRepository->destroy($item['id']);
$creates[0] = $attributes;
break;
case 2:
$this->flowPoolSettingRepository->destroy($item['id']);
$creates[0] = $attributes;
unset($item['id']);
$creates[1] = $item->toArray();
$creates[1]['end_at'] = Carbon::parse($attributes['start_at'])->subMonth()->endOfMonth()->format('Y-m-d H:i:s');
$creates[2] = $item->toArray();
$creates[2]['start_at'] = Carbon::parse($attributes['end_at'])->addMonth()->startOfMonth()->format('Y-m-d H:i:s');
break 2;
case 3:
case 4:
$creates[0] = $attributes;
break;
case 5:
$creates[0] = $attributes;
$item['start_at'] = Carbon::parse($attributes['end_at'])->addMonth()->startOfMonth()->format('Y-m-d H:i:s');
$this->flowPoolSettingRepository->where(['id' => $item['id']])->update($item);
break;
case 6:
$creates[0] = $attributes;
$item['end_at'] = Carbon::parse($attributes['start_at'])->subMonth()->startOfMonth()->format('Y-m-d H:i:s');
$this->flowPoolSettingRepository->where(['id' => $item['id']])->update($item);
break;
default:
$creates[0] = $attributes;
break;
}
}
} else {
$creates[0] = $attributes;
$creates[0]['start_at'] = '2000-01-01 00:00:00';
$creates[0]['end_at'] !== '3000-01-01 23:59:59';
}
$maxId = FlowPoolSetting::withTrashed()->max('id') ?? 0;
foreach ($creates as $key => $create) {
$create['id'] = ++$maxId;
if ($key) {
$this->flowPoolSettingRepository->create($create);
} else {
$node =$this->flowPoolSettingRepository->create($create);
}
}
});
}
if ($attributes['id']) {
$node = $this->flowPoolSettingRepository->find($attributes['id']);
if (!$node) {
throw new NotExistException('规则不存在或已删除');
}
if ($node->start_at !== $attributes['start_at'] || $node->end_at !== $attributes['end_at']) {
throw new InvalidArgumentException('起止时间不能修改');
}
$this->flowPoolSettingRepository->setModel($node)->update($attributes);
}
return $node;
}
public static function sn($id)
{
return sprintf('FP%011d', $id);
}
public function load($id)
{
if (!$this->pools) {
$this->pools = $this->flowPoolRepository->withTrashed()->get()->keyBy('id');
}
return $this->pools[$id];
}
}