Viewing file: LeadController.php (23.51 KB) -rw-rw-rw- Select action/file-type: (+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
<?php
namespace Webkul\Admin\Http\Controllers\Lead;
use Carbon\Carbon; use Illuminate\Http\JsonResponse; use Illuminate\Http\RedirectResponse; use Illuminate\Http\Resources\Json\AnonymousResourceCollection; use Illuminate\Support\Facades\Event; use Illuminate\Support\Facades\Validator; use Illuminate\View\View; use Prettus\Repository\Criteria\RequestCriteria; use Webkul\Admin\DataGrids\Lead\LeadDataGrid; use Webkul\Admin\Http\Controllers\Controller; use Webkul\Admin\Http\Requests\LeadForm; use Webkul\Admin\Http\Requests\MassDestroyRequest; use Webkul\Admin\Http\Requests\MassUpdateRequest; use Webkul\Admin\Http\Resources\LeadResource; use Webkul\Admin\Http\Resources\StageResource; use Webkul\Attribute\Repositories\AttributeRepository; use Webkul\Contact\Repositories\PersonRepository; use Webkul\Lead\Helpers\MagicAI; use Webkul\Lead\Repositories\LeadRepository; use Webkul\Lead\Repositories\PipelineRepository; use Webkul\Lead\Repositories\ProductRepository; use Webkul\Lead\Repositories\SourceRepository; use Webkul\Lead\Repositories\StageRepository; use Webkul\Lead\Repositories\TypeRepository; use Webkul\Lead\Services\MagicAIService; use Webkul\Tag\Repositories\TagRepository; use Webkul\User\Repositories\UserRepository;
class LeadController extends Controller { /** * Const variable for supported types. */ const SUPPORTED_TYPES = 'pdf,bmp,jpeg,jpg,png,webp';
/** * Create a new controller instance. * * @return void */ public function __construct( protected UserRepository $userRepository, protected AttributeRepository $attributeRepository, protected SourceRepository $sourceRepository, protected TypeRepository $typeRepository, protected PipelineRepository $pipelineRepository, protected StageRepository $stageRepository, protected LeadRepository $leadRepository, protected ProductRepository $productRepository, protected PersonRepository $personRepository ) { request()->request->add(['entity_type' => 'leads']); }
/** * Display a listing of the resource. */ public function index() { if (request()->ajax()) { return datagrid(LeadDataGrid::class)->process(); }
if (request('pipeline_id')) { $pipeline = $this->pipelineRepository->find(request('pipeline_id')); } else { $pipeline = $this->pipelineRepository->getDefaultPipeline(); }
return view('admin::leads.index', [ 'pipeline' => $pipeline, 'columns' => $this->getKanbanColumns(), ]); }
/** * Returns a listing of the resource. */ public function get(): JsonResponse { if (request()->query('pipeline_id')) { $pipeline = $this->pipelineRepository->find(request()->query('pipeline_id')); } else { $pipeline = $this->pipelineRepository->getDefaultPipeline(); }
if ($stageId = request()->query('pipeline_stage_id')) { $stages = $pipeline->stages->where('id', request()->query('pipeline_stage_id')); } else { $stages = $pipeline->stages; }
foreach ($stages as $stage) { /** * We have to create a new instance of the lead repository every time, which is * why we're not using the injected one. */ $query = app(LeadRepository::class) ->pushCriteria(app(RequestCriteria::class)) ->where([ 'lead_pipeline_id' => $pipeline->id, 'lead_pipeline_stage_id' => $stage->id, ]);
if ($userIds = bouncer()->getAuthorizedUserIds()) { $query->whereIn('leads.user_id', $userIds); }
$stage->lead_value = (clone $query)->sum('lead_value');
$data[$stage->sort_order] = (new StageResource($stage))->jsonSerialize();
$data[$stage->sort_order]['leads'] = [ 'data' => LeadResource::collection($paginator = $query->with([ 'tags', 'type', 'source', 'user', 'person', 'person.organization', 'pipeline', 'pipeline.stages', 'stage', 'attribute_values', ])->paginate(10)),
'meta' => [ 'current_page' => $paginator->currentPage(), 'from' => $paginator->firstItem(), 'last_page' => $paginator->lastPage(), 'per_page' => $paginator->perPage(), 'to' => $paginator->lastItem(), 'total' => $paginator->total(), ], ]; }
return response()->json($data); }
/** * Show the form for creating a new resource. */ public function create(): View { return view('admin::leads.create'); }
/** * Store a newly created resource in storage. */ public function store(LeadForm $request): RedirectResponse|JsonResponse { Event::dispatch('lead.create.before');
$data = request()->all();
$data['status'] = 1;
if (! empty($data['lead_pipeline_stage_id'])) { $stage = $this->stageRepository->findOrFail($data['lead_pipeline_stage_id']);
$data['lead_pipeline_id'] = $stage->lead_pipeline_id; } else { if (empty($data['lead_pipeline_id'])) { $pipeline = $this->pipelineRepository->getDefaultPipeline();
$data['lead_pipeline_id'] = $pipeline->id; } else { $pipeline = $this->pipelineRepository->findOrFail($data['lead_pipeline_id']); }
$stage = $pipeline->stages()->first();
$data['lead_pipeline_stage_id'] = $stage->id; }
if (in_array($stage->code, ['won', 'lost'])) { $data['closed_at'] = Carbon::now(); }
$lead = $this->leadRepository->create($data);
if (request()->ajax()) { return response()->json([ 'message' => trans('admin::app.leads.create-success'), 'data' => new LeadResource($lead), ]); }
Event::dispatch('lead.create.after', $lead);
session()->flash('success', trans('admin::app.leads.create-success'));
if (! empty($data['lead_pipeline_id'])) { $params['pipeline_id'] = $data['lead_pipeline_id']; }
return redirect()->route('admin.leads.index', $params ?? []); }
/** * Show the form for editing the specified resource. */ public function edit(int $id): View { $lead = $this->leadRepository->findOrFail($id);
return view('admin::leads.edit', compact('lead')); }
/** * Display a resource. */ public function view(int $id) { $lead = $this->leadRepository->findOrFail($id);
$userIds = bouncer()->getAuthorizedUserIds();
if ( $userIds && ! in_array($lead->user_id, $userIds) ) { return redirect()->route('admin.leads.index'); }
return view('admin::leads.view', compact('lead')); }
/** * Update the specified resource in storage. */ public function update(LeadForm $request, int $id): RedirectResponse|JsonResponse { Event::dispatch('lead.update.before', $id);
$data = $request->all();
if (isset($data['lead_pipeline_stage_id'])) { $stage = $this->stageRepository->findOrFail($data['lead_pipeline_stage_id']);
$data['lead_pipeline_id'] = $stage->lead_pipeline_id; } else { $pipeline = $this->pipelineRepository->getDefaultPipeline();
$stage = $pipeline->stages()->first();
$data['lead_pipeline_id'] = $pipeline->id;
$data['lead_pipeline_stage_id'] = $stage->id; }
$lead = $this->leadRepository->update($data, $id);
Event::dispatch('lead.update.after', $lead);
if (request()->ajax()) { return response()->json([ 'message' => trans('admin::app.leads.update-success'), ]); }
session()->flash('success', trans('admin::app.leads.update-success'));
if (request()->has('closed_at')) { return redirect()->back(); } else { return redirect()->route('admin.leads.index', $data['lead_pipeline_id']); } }
/** * Update the lead attributes. */ public function updateAttributes(int $id) { $data = request()->all();
$attributes = $this->attributeRepository->findWhere([ 'entity_type' => 'leads', ['code', 'NOTIN', ['title', 'description']], ]);
Event::dispatch('lead.update.before', $id);
$lead = $this->leadRepository->update($data, $id, $attributes);
Event::dispatch('lead.update.after', $lead);
return response()->json([ 'message' => trans('admin::app.leads.update-success'), ]); }
/** * Update the lead stage. */ public function updateStage(int $id) { $this->validate(request(), [ 'lead_pipeline_stage_id' => 'required', ]);
$lead = $this->leadRepository->findOrFail($id);
$stage = $lead->pipeline->stages() ->where('id', request()->input('lead_pipeline_stage_id')) ->firstOrFail();
Event::dispatch('lead.update.before', $id);
$payload = request()->merge([ 'entity_type' => 'leads', 'lead_pipeline_stage_id' => $stage->id, ])->only([ 'closed_at', 'lost_reason', 'lead_pipeline_stage_id', 'entity_type', ]);
$lead = $this->leadRepository->update($payload, $id, ['lead_pipeline_stage_id']);
Event::dispatch('lead.update.after', $lead);
return response()->json([ 'message' => trans('admin::app.leads.update-success'), ]); }
/** * Search person results. */ public function search(): AnonymousResourceCollection { if ($userIds = bouncer()->getAuthorizedUserIds()) { $results = $this->leadRepository ->pushCriteria(app(RequestCriteria::class)) ->findWhereIn('user_id', $userIds); } else { $results = $this->leadRepository ->pushCriteria(app(RequestCriteria::class)) ->all(); }
return LeadResource::collection($results); }
/** * Remove the specified resource from storage. */ public function destroy(int $id): JsonResponse { $this->leadRepository->findOrFail($id);
try { Event::dispatch('lead.delete.before', $id);
$this->leadRepository->delete($id);
Event::dispatch('lead.delete.after', $id);
return response()->json([ 'message' => trans('admin::app.leads.destroy-success'), ]); } catch (\Exception $exception) { return response()->json([ 'message' => trans('admin::app.leads.destroy-failed'), ], 400); } }
/** * Mass update the specified resources. */ public function massUpdate(MassUpdateRequest $massUpdateRequest): JsonResponse { $leads = $this->leadRepository->findWhereIn('id', $massUpdateRequest->input('indices'));
try { foreach ($leads as $lead) { Event::dispatch('lead.update.before', $lead->id);
$lead = $this->leadRepository->find($lead->id);
$lead?->update(['lead_pipeline_stage_id' => $massUpdateRequest->input('value')]);
Event::dispatch('lead.update.before', $lead->id); }
return response()->json([ 'message' => trans('admin::app.leads.update-success'), ]); } catch (\Exception $th) { return response()->json([ 'message' => trans('admin::app.leads.update-failed'), ], 400); } }
/** * Mass delete the specified resources. */ public function massDestroy(MassDestroyRequest $massDestroyRequest): JsonResponse { $leads = $this->leadRepository->findWhereIn('id', $massDestroyRequest->input('indices'));
try { foreach ($leads as $lead) { Event::dispatch('lead.delete.before', $lead->id);
$this->leadRepository->delete($lead->id);
Event::dispatch('lead.delete.after', $lead->id); }
return response()->json([ 'message' => trans('admin::app.leads.destroy-success'), ]); } catch (\Exception $exception) { return response()->json([ 'message' => trans('admin::app.leads.destroy-failed'), ]); } }
/** * Attach product to lead. */ public function addProduct(int $leadId): JsonResponse { $product = $this->productRepository->updateOrCreate( [ 'lead_id' => $leadId, 'product_id' => request()->input('product_id'), ], array_merge( request()->all(), [ 'lead_id' => $leadId, 'amount' => request()->input('price') * request()->input('quantity'), ], ) );
return response()->json([ 'data' => $product, 'message' => trans('admin::app.leads.update-success'), ]); }
/** * Remove product attached to lead. */ public function removeProduct(int $id): JsonResponse { try { Event::dispatch('lead.product.delete.before', $id);
$this->productRepository->deleteWhere([ 'lead_id' => $id, 'product_id' => request()->input('product_id'), ]);
Event::dispatch('lead.product.delete.after', $id);
return response()->json([ 'message' => trans('admin::app.leads.destroy-success'), ]); } catch (\Exception $exception) { return response()->json([ 'message' => trans('admin::app.leads.destroy-failed'), ]); } }
/** * Kanban lookup. */ public function kanbanLookup() { $params = $this->validate(request(), [ 'column' => ['required'], 'search' => ['required', 'min:2'], ]);
/** * Finding the first column from the collection. */ $column = collect($this->getKanbanColumns())->where('index', $params['column'])->firstOrFail();
/** * Fetching on the basis of column options. */ return app($column['filterable_options']['repository']) ->select([$column['filterable_options']['column']['label'].' as label', $column['filterable_options']['column']['value'].' as value']) ->where($column['filterable_options']['column']['label'], 'LIKE', '%'.$params['search'].'%') ->get() ->map ->only('label', 'value'); }
/** * Get columns for the kanban view. */ private function getKanbanColumns(): array { return [ [ 'index' => 'id', 'label' => trans('admin::app.leads.index.kanban.columns.id'), 'type' => 'integer', 'searchable' => false, 'search_field' => 'in', 'filterable' => true, 'filterable_type' => null, 'filterable_options' => [], 'allow_multiple_values' => true, 'sortable' => true, 'visibility' => true, ], [ 'index' => 'lead_value', 'label' => trans('admin::app.leads.index.kanban.columns.lead-value'), 'type' => 'string', 'searchable' => false, 'search_field' => 'in', 'filterable' => true, 'filterable_type' => null, 'filterable_options' => [], 'allow_multiple_values' => true, 'sortable' => true, 'visibility' => true, ], [ 'index' => 'user_id', 'label' => trans('admin::app.leads.index.kanban.columns.sales-person'), 'type' => 'string', 'searchable' => false, 'search_field' => 'in', 'filterable' => true, 'filterable_type' => 'searchable_dropdown', 'filterable_options' => [ 'repository' => UserRepository::class, 'column' => [ 'label' => 'name', 'value' => 'id', ], ], 'allow_multiple_values' => true, 'sortable' => true, 'visibility' => true, ], [ 'index' => 'person.id', 'label' => trans('admin::app.leads.index.kanban.columns.contact-person'), 'type' => 'string', 'searchable' => false, 'search_field' => 'in', 'filterable' => true, 'filterable_options' => [], 'allow_multiple_values' => true, 'sortable' => true, 'visibility' => true, 'filterable_type' => 'searchable_dropdown', 'filterable_options' => [ 'repository' => PersonRepository::class, 'column' => [ 'label' => 'name', 'value' => 'id', ], ], ], [ 'index' => 'lead_type_id', 'label' => trans('admin::app.leads.index.kanban.columns.lead-type'), 'type' => 'string', 'searchable' => false, 'search_field' => 'in', 'filterable' => true, 'filterable_type' => 'dropdown', 'filterable_options' => $this->typeRepository->all(['name as label', 'id as value'])->toArray(), 'allow_multiple_values' => true, 'sortable' => true, 'visibility' => true, ], [ 'index' => 'lead_source_id', 'label' => trans('admin::app.leads.index.kanban.columns.source'), 'type' => 'string', 'searchable' => false, 'search_field' => 'in', 'filterable' => true, 'filterable_type' => 'dropdown', 'filterable_options' => $this->sourceRepository->all(['name as label', 'id as value'])->toArray(), 'allow_multiple_values' => true, 'sortable' => true, 'visibility' => true, ], [ 'index' => 'tags.name', 'label' => trans('admin::app.leads.index.kanban.columns.tags'), 'type' => 'string', 'searchable' => false, 'search_field' => 'in', 'filterable' => true, 'filterable_options' => [], 'allow_multiple_values' => true, 'sortable' => true, 'visibility' => true, 'filterable_type' => 'searchable_dropdown', 'filterable_options' => [ 'repository' => TagRepository::class, 'column' => [ 'label' => 'name', 'value' => 'name', ], ], ], ]; }
/** * Create lead with specified AI. */ public function createByAI() { $leadData = [];
$errorMessages = [];
foreach (request()->file('files') as $file) { $lead = $this->processFile($file);
if ( isset($lead['status']) && $lead['status'] === 'error' ) { $errorMessages[] = $lead['message']; } else { $leadData[] = $lead; } }
if (isset($errorMessages[0]['code'])) { return response()->json(MagicAI::errorHandler($errorMessages[0]['message'])); }
if ( empty($leadData) && ! empty($errorMessages) ) { return response()->json(MagicAI::errorHandler(implode(', ', $errorMessages)), 400); }
if (empty($leadData)) { return response()->json(MagicAI::errorHandler(trans('admin::app.leads.no-valid-files')), 400); }
return response()->json([ 'message' => trans('admin::app.leads.create-success'), 'leads' => $this->createLeads($leadData), ]); }
/** * Process file. * * @param mixed $file */ private function processFile($file) { $validator = Validator::make( ['file' => $file], ['file' => 'required|extensions:'.str_replace(' ', '', self::SUPPORTED_TYPES)] );
if ($validator->fails()) { return MagicAI::errorHandler($validator->errors()->first()); }
$base64Pdf = base64_encode(file_get_contents($file->getRealPath()));
$extractedData = MagicAIService::extractDataFromFile($base64Pdf);
$lead = MagicAI::mapAIDataToLead($extractedData);
return $lead; }
/** * Create multiple leads. */ private function createLeads($rawLeads): array { $leads = [];
foreach ($rawLeads as $rawLead) { Event::dispatch('lead.create.before');
foreach ($rawLead['person']['emails'] as $email) { $person = $this->personRepository ->whereJsonContains('emails', [['value' => $email['value']]]) ->first();
if ($person) { $rawLead['person']['id'] = $person->id;
break; } }
$pipeline = $this->pipelineRepository->getDefaultPipeline();
$stage = $pipeline->stages()->first();
$lead = $this->leadRepository->create(array_merge($rawLead, [ 'lead_pipeline_id' => $pipeline->id, 'lead_pipeline_stage_id' => $stage->id, ]));
Event::dispatch('lead.create.after', $lead);
$leads[] = $lead; }
return $leads; } }
|