add: full multi-tenancy control
This commit is contained in:
254
packages/Webkul/Lead/src/Repositories/LeadRepository.php
Executable file
254
packages/Webkul/Lead/src/Repositories/LeadRepository.php
Executable file
@@ -0,0 +1,254 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Lead\Repositories;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Container\Container;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Str;
|
||||
use Webkul\Attribute\Repositories\AttributeRepository;
|
||||
use Webkul\Attribute\Repositories\AttributeValueRepository;
|
||||
use Webkul\Contact\Repositories\PersonRepository;
|
||||
use Webkul\Core\Eloquent\Repository;
|
||||
use Webkul\Lead\Contracts\Lead;
|
||||
|
||||
class LeadRepository extends Repository
|
||||
{
|
||||
/**
|
||||
* Searchable fields.
|
||||
*/
|
||||
protected $fieldSearchable = [
|
||||
'title',
|
||||
'lead_value',
|
||||
'status',
|
||||
'user_id',
|
||||
'user.name',
|
||||
'person_id',
|
||||
'person.name',
|
||||
'lead_source_id',
|
||||
'lead_type_id',
|
||||
'lead_pipeline_id',
|
||||
'lead_pipeline_stage_id',
|
||||
'created_at',
|
||||
'closed_at',
|
||||
'expected_close_date',
|
||||
];
|
||||
|
||||
/**
|
||||
* Create a new repository instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(
|
||||
protected StageRepository $stageRepository,
|
||||
protected PersonRepository $personRepository,
|
||||
protected ProductRepository $productRepository,
|
||||
protected AttributeRepository $attributeRepository,
|
||||
protected AttributeValueRepository $attributeValueRepository,
|
||||
Container $container
|
||||
) {
|
||||
parent::__construct($container);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify model class name.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function model()
|
||||
{
|
||||
return Lead::class;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get leads query.
|
||||
*
|
||||
* @param int $pipelineId
|
||||
* @param int $pipelineStageId
|
||||
* @param string $term
|
||||
* @param string $createdAtRange
|
||||
* @return mixed
|
||||
*/
|
||||
public function getLeadsQuery($pipelineId, $pipelineStageId, $term, $createdAtRange)
|
||||
{
|
||||
return $this->with([
|
||||
'attribute_values',
|
||||
'pipeline',
|
||||
'stage',
|
||||
])->scopeQuery(function ($query) use ($pipelineId, $pipelineStageId, $term, $createdAtRange) {
|
||||
return $query->select(
|
||||
'leads.id as id',
|
||||
'leads.created_at as created_at',
|
||||
'title',
|
||||
'lead_value',
|
||||
'persons.name as person_name',
|
||||
'leads.person_id as person_id',
|
||||
'lead_pipelines.id as lead_pipeline_id',
|
||||
'lead_pipeline_stages.name as status',
|
||||
'lead_pipeline_stages.id as lead_pipeline_stage_id'
|
||||
)
|
||||
->addSelect(DB::raw('DATEDIFF('.DB::getTablePrefix().'leads.created_at + INTERVAL lead_pipelines.rotten_days DAY, now()) as rotten_days'))
|
||||
->leftJoin('persons', 'leads.person_id', '=', 'persons.id')
|
||||
->leftJoin('lead_pipelines', 'leads.lead_pipeline_id', '=', 'lead_pipelines.id')
|
||||
->leftJoin('lead_pipeline_stages', 'leads.lead_pipeline_stage_id', '=', 'lead_pipeline_stages.id')
|
||||
->where('title', 'like', "%$term%")
|
||||
->where('leads.lead_pipeline_id', $pipelineId)
|
||||
->where('leads.lead_pipeline_stage_id', $pipelineStageId)
|
||||
->when($createdAtRange, function ($query) use ($createdAtRange) {
|
||||
return $query->whereBetween('leads.created_at', $createdAtRange);
|
||||
})
|
||||
->where(function ($query) {
|
||||
if ($userIds = bouncer()->getAuthorizedUserIds()) {
|
||||
$query->whereIn('leads.user_id', $userIds);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Create.
|
||||
*
|
||||
* @return \Webkul\Lead\Contracts\Lead
|
||||
*/
|
||||
public function create(array $data)
|
||||
{
|
||||
/**
|
||||
* If a person is provided, create or update the person and set the `person_id`.
|
||||
*/
|
||||
if (isset($data['person'])) {
|
||||
if (! empty($data['person']['id'])) {
|
||||
$person = $this->personRepository->findOrFail($data['person']['id']);
|
||||
} else {
|
||||
$person = $this->personRepository->create(array_merge($data['person'], [
|
||||
'entity_type' => 'persons',
|
||||
]));
|
||||
}
|
||||
|
||||
$data['person_id'] = $person->id;
|
||||
}
|
||||
|
||||
if (empty($data['expected_close_date'])) {
|
||||
$data['expected_close_date'] = null;
|
||||
}
|
||||
|
||||
$lead = parent::create(array_merge([
|
||||
'lead_pipeline_id' => 1,
|
||||
'lead_pipeline_stage_id' => 1,
|
||||
], $data));
|
||||
|
||||
$this->attributeValueRepository->save(array_merge($data, [
|
||||
'entity_id' => $lead->id,
|
||||
]));
|
||||
|
||||
if (isset($data['products'])) {
|
||||
foreach ($data['products'] as $product) {
|
||||
$this->productRepository->create(array_merge($product, [
|
||||
'lead_id' => $lead->id,
|
||||
'amount' => $product['price'] * $product['quantity'],
|
||||
]));
|
||||
}
|
||||
}
|
||||
|
||||
return $lead;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update.
|
||||
*
|
||||
* @param int $id
|
||||
* @param array|\Illuminate\Database\Eloquent\Collection $attributes
|
||||
* @return \Webkul\Lead\Contracts\Lead
|
||||
*/
|
||||
public function update(array $data, $id, $attributes = [])
|
||||
{
|
||||
/**
|
||||
* If a person is provided, create or update the person and set the `person_id`.
|
||||
* Be cautious, as a lead can be updated without providing person data.
|
||||
* For example, in the lead Kanban section, when switching stages, only the stage will be updated.
|
||||
*/
|
||||
if (isset($data['person'])) {
|
||||
if (! empty($data['person']['id'])) {
|
||||
$person = $this->personRepository->findOrFail($data['person']['id']);
|
||||
} else {
|
||||
$person = $this->personRepository->create(array_merge($data['person'], [
|
||||
'entity_type' => 'persons',
|
||||
]));
|
||||
}
|
||||
|
||||
$data['person_id'] = $person->id;
|
||||
}
|
||||
|
||||
if (isset($data['lead_pipeline_stage_id'])) {
|
||||
$stage = $this->stageRepository->find($data['lead_pipeline_stage_id']);
|
||||
|
||||
if (in_array($stage->code, ['won', 'lost'])) {
|
||||
$data['closed_at'] = $data['closed_at'] ?? Carbon::now();
|
||||
} else {
|
||||
$data['closed_at'] = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($data['expected_close_date'])) {
|
||||
$data['expected_close_date'] = null;
|
||||
}
|
||||
|
||||
$lead = parent::update($data, $id);
|
||||
|
||||
/**
|
||||
* If attributes are provided, only save the provided attributes and return.
|
||||
* A collection of attributes may also be provided, which will be treated as valid,
|
||||
* regardless of whether it is empty or not.
|
||||
*/
|
||||
if (! empty($attributes)) {
|
||||
/**
|
||||
* If attributes are provided as an array, then fetch the attributes from the database;
|
||||
* otherwise, use the provided collection of attributes.
|
||||
*/
|
||||
if (is_array($attributes)) {
|
||||
$conditions = ['entity_type' => $data['entity_type']];
|
||||
|
||||
if (isset($data['quick_add'])) {
|
||||
$conditions['quick_add'] = 1;
|
||||
}
|
||||
|
||||
$attributes = $this->attributeRepository->where($conditions)
|
||||
->whereIn('code', $attributes)
|
||||
->get();
|
||||
}
|
||||
|
||||
$this->attributeValueRepository->save(array_merge($data, [
|
||||
'entity_id' => $lead->id,
|
||||
]), $attributes);
|
||||
|
||||
return $lead;
|
||||
}
|
||||
|
||||
$this->attributeValueRepository->save(array_merge($data, [
|
||||
'entity_id' => $lead->id,
|
||||
]));
|
||||
|
||||
$previousProductIds = $lead->products()->pluck('id');
|
||||
|
||||
if (isset($data['products'])) {
|
||||
foreach ($data['products'] as $productId => $productInputs) {
|
||||
if (Str::contains($productId, 'product_')) {
|
||||
$this->productRepository->create(array_merge([
|
||||
'lead_id' => $lead->id,
|
||||
], $productInputs));
|
||||
} else {
|
||||
if (is_numeric($index = $previousProductIds->search($productId))) {
|
||||
$previousProductIds->forget($index);
|
||||
}
|
||||
|
||||
$this->productRepository->update($productInputs, $productId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($previousProductIds as $productId) {
|
||||
$this->productRepository->delete($productId);
|
||||
}
|
||||
|
||||
return $lead;
|
||||
}
|
||||
}
|
||||
114
packages/Webkul/Lead/src/Repositories/PipelineRepository.php
Executable file
114
packages/Webkul/Lead/src/Repositories/PipelineRepository.php
Executable file
@@ -0,0 +1,114 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Lead\Repositories;
|
||||
|
||||
use Illuminate\Container\Container;
|
||||
use Illuminate\Support\Str;
|
||||
use Webkul\Core\Eloquent\Repository;
|
||||
|
||||
class PipelineRepository extends Repository
|
||||
{
|
||||
/**
|
||||
* Create a new repository instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(
|
||||
protected StageRepository $stageRepository,
|
||||
Container $container
|
||||
) {
|
||||
parent::__construct($container);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify model class name.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function model()
|
||||
{
|
||||
return 'Webkul\Lead\Contracts\Pipeline';
|
||||
}
|
||||
|
||||
/**
|
||||
* Create pipeline.
|
||||
*
|
||||
* @return \Webkul\Lead\Contracts\Pipeline
|
||||
*/
|
||||
public function create(array $data)
|
||||
{
|
||||
if ($data['is_default'] ?? false) {
|
||||
$this->model->query()->update(['is_default' => 0]);
|
||||
}
|
||||
|
||||
$pipeline = $this->model->create($data);
|
||||
|
||||
foreach ($data['stages'] as $stageData) {
|
||||
$this->stageRepository->create(array_merge([
|
||||
'lead_pipeline_id' => $pipeline->id,
|
||||
], $stageData));
|
||||
}
|
||||
|
||||
return $pipeline;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update pipeline.
|
||||
*
|
||||
* @param int $id
|
||||
* @param string $attribute
|
||||
* @return \Webkul\Lead\Contracts\Pipeline
|
||||
*/
|
||||
public function update(array $data, $id, $attribute = 'id')
|
||||
{
|
||||
$pipeline = $this->find($id);
|
||||
|
||||
if ($data['is_default'] ?? false) {
|
||||
$this->model->query()->where('id', '<>', $id)->update(['is_default' => 0]);
|
||||
}
|
||||
|
||||
$pipeline->update($data);
|
||||
|
||||
$previousStageIds = $pipeline->stages()->pluck('id');
|
||||
|
||||
foreach ($data['stages'] as $stageId => $stageData) {
|
||||
if (Str::contains($stageId, 'stage_')) {
|
||||
$this->stageRepository->create(array_merge([
|
||||
'lead_pipeline_id' => $pipeline->id,
|
||||
], $stageData));
|
||||
} else {
|
||||
if (is_numeric($index = $previousStageIds->search($stageId))) {
|
||||
$previousStageIds->forget($index);
|
||||
}
|
||||
|
||||
$this->stageRepository->update($stageData, $stageId);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($previousStageIds as $stageId) {
|
||||
$pipeline->leads()->where('lead_pipeline_stage_id', $stageId)->update([
|
||||
'lead_pipeline_stage_id' => $pipeline->stages()->first()->id,
|
||||
]);
|
||||
|
||||
$this->stageRepository->delete($stageId);
|
||||
}
|
||||
|
||||
return $pipeline;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the default pipeline.
|
||||
*
|
||||
* @return \Webkul\Lead\Contracts\Pipeline
|
||||
*/
|
||||
public function getDefaultPipeline()
|
||||
{
|
||||
$pipeline = $this->findOneByField('is_default', 1);
|
||||
|
||||
if (! $pipeline) {
|
||||
$pipeline = $this->first();
|
||||
}
|
||||
|
||||
return $pipeline;
|
||||
}
|
||||
}
|
||||
18
packages/Webkul/Lead/src/Repositories/ProductRepository.php
Executable file
18
packages/Webkul/Lead/src/Repositories/ProductRepository.php
Executable file
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Lead\Repositories;
|
||||
|
||||
use Webkul\Core\Eloquent\Repository;
|
||||
|
||||
class ProductRepository extends Repository
|
||||
{
|
||||
/**
|
||||
* Specify Model class name
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function model()
|
||||
{
|
||||
return 'Webkul\Lead\Contracts\Product';
|
||||
}
|
||||
}
|
||||
18
packages/Webkul/Lead/src/Repositories/SourceRepository.php
Executable file
18
packages/Webkul/Lead/src/Repositories/SourceRepository.php
Executable file
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Lead\Repositories;
|
||||
|
||||
use Webkul\Core\Eloquent\Repository;
|
||||
|
||||
class SourceRepository extends Repository
|
||||
{
|
||||
/**
|
||||
* Specify Model class name
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function model()
|
||||
{
|
||||
return 'Webkul\Lead\Contracts\Source';
|
||||
}
|
||||
}
|
||||
18
packages/Webkul/Lead/src/Repositories/StageRepository.php
Normal file
18
packages/Webkul/Lead/src/Repositories/StageRepository.php
Normal file
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Lead\Repositories;
|
||||
|
||||
use Webkul\Core\Eloquent\Repository;
|
||||
|
||||
class StageRepository extends Repository
|
||||
{
|
||||
/**
|
||||
* Specify Model class name
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function model()
|
||||
{
|
||||
return 'Webkul\Lead\Contracts\Stage';
|
||||
}
|
||||
}
|
||||
18
packages/Webkul/Lead/src/Repositories/TypeRepository.php
Executable file
18
packages/Webkul/Lead/src/Repositories/TypeRepository.php
Executable file
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Lead\Repositories;
|
||||
|
||||
use Webkul\Core\Eloquent\Repository;
|
||||
|
||||
class TypeRepository extends Repository
|
||||
{
|
||||
/**
|
||||
* Specify Model class name
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function model()
|
||||
{
|
||||
return 'Webkul\Lead\Contracts\Type';
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user