snapshot of https://github.com/krayin/laravel-crm.git (2.2, 2026-09-18; blobs > 131072B omitted)
Some checks failed
Admin | Playwright Tests / Admin | Playwright Tests | Shard 1 Of 6 (push) Failing after 37s
Admin | Playwright Tests / Admin | Playwright Tests | Shard 2 Of 6 (push) Failing after 7s
Admin | Playwright Tests / Admin | Playwright Tests | Shard 4 Of 6 (push) Failing after 7s
Admin | Playwright Tests / Admin | Playwright Tests | Shard 6 Of 6 (push) Failing after 6s
Linting Tests / PHP 8.3 test on ubuntu-latest (push) Failing after 5s
CI / PHP 8.3 test on ubuntu-latest (push) Failing after 6s
Skills Consistency / validate-skills (push) Successful in 10s
Admin | Playwright Tests / Admin | Playwright Tests | Shard 3 Of 6 (push) Failing after 7s
Admin | Playwright Tests / Admin | Playwright Tests | Shard 5 Of 6 (push) Failing after 6s

This commit is contained in:
upstream-mirror
2026-09-18 04:37:41 +05:00
commit 135ffdb085
1274 changed files with 144880 additions and 0 deletions

View File

@@ -0,0 +1,267 @@
<?php
namespace Webkul\Lead\Repositories;
use Carbon\Carbon;
use Illuminate\Container\Container;
use Illuminate\Database\Eloquent\Collection;
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 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 {
/**
* Assign the person to the lead owner (falling back to the current user) so that the
* person is not created with a null `user_id`, which would otherwise hide it from the
* person listing for users restricted to group/individual data scope.
*/
$person = $this->personRepository->create(array_merge($data['person'], [
'entity_type' => 'persons',
'user_id' => $data['user_id'] ?? auth()->guard('user')->id(),
]));
}
$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|Collection $attributes
* @return 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 {
/**
* Assign the person to the lead owner (falling back to the current user) so that the
* person is not created with a null `user_id`, which would otherwise hide it from the
* person listing for users restricted to group/individual data scope.
*/
$person = $this->personRepository->create(array_merge($data['person'], [
'entity_type' => 'persons',
'user_id' => $data['user_id'] ?? auth()->guard('user')->id(),
]));
}
$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;
}
}