add: full multi-tenancy control
This commit is contained in:
28
packages/Webkul/Activity/composer.json
Executable file
28
packages/Webkul/Activity/composer.json
Executable file
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"name": "krayin/laravel-activity",
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Jitendra Singh",
|
||||
"email": "jitendra@webkul.com"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"krayin/laravel-core": "^1.0",
|
||||
"krayin/laravel-user": "^1.0"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Webkul\\Activity\\": "src/"
|
||||
}
|
||||
},
|
||||
"extra": {
|
||||
"laravel": {
|
||||
"providers": [
|
||||
"Webkul\\Activity\\Providers\\ActivityServiceProvider"
|
||||
],
|
||||
"aliases": {}
|
||||
}
|
||||
},
|
||||
"minimum-stability": "dev"
|
||||
}
|
||||
5
packages/Webkul/Activity/src/Contracts/Activity.php
Normal file
5
packages/Webkul/Activity/src/Contracts/Activity.php
Normal file
@@ -0,0 +1,5 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Activity\Contracts;
|
||||
|
||||
interface Activity {}
|
||||
5
packages/Webkul/Activity/src/Contracts/File.php
Normal file
5
packages/Webkul/Activity/src/Contracts/File.php
Normal file
@@ -0,0 +1,5 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Activity\Contracts;
|
||||
|
||||
interface File {}
|
||||
5
packages/Webkul/Activity/src/Contracts/Participant.php
Normal file
5
packages/Webkul/Activity/src/Contracts/Participant.php
Normal file
@@ -0,0 +1,5 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Activity\Contracts;
|
||||
|
||||
interface Participant {}
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('activities', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->string('title')->nullable();
|
||||
$table->string('type');
|
||||
$table->text('comment')->nullable();
|
||||
$table->json('additional')->nullable();
|
||||
$table->datetime('schedule_from')->nullable();
|
||||
$table->datetime('schedule_to')->nullable();
|
||||
$table->boolean('is_done')->default(0);
|
||||
|
||||
$table->integer('user_id')->unsigned();
|
||||
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('activities');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('activity_files', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->string('name');
|
||||
$table->string('path');
|
||||
|
||||
$table->integer('activity_id')->unsigned();
|
||||
$table->foreign('activity_id')->references('id')->on('activities')->onDelete('cascade');
|
||||
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('activity_files');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('activity_participants', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
|
||||
$table->integer('activity_id')->unsigned();
|
||||
$table->foreign('activity_id')->references('id')->on('activities')->onDelete('cascade');
|
||||
|
||||
$table->integer('user_id')->nullable()->unsigned();
|
||||
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
|
||||
|
||||
$table->integer('person_id')->nullable()->unsigned();
|
||||
$table->foreign('person_id')->references('id')->on('persons')->onDelete('cascade');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('activity_participants');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('activities', function (Blueprint $table) {
|
||||
$table->string('location')->nullable();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('activities', function (Blueprint $table) {
|
||||
$table->dropColumn('location');
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('activities', function (Blueprint $table) {
|
||||
$table->dropForeign(['user_id']);
|
||||
|
||||
$table->unsignedInteger('user_id')->nullable()->change();
|
||||
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('activities', function (Blueprint $table) {
|
||||
$tablePrefix = DB::getTablePrefix();
|
||||
|
||||
// Disable foreign key checks temporarily.
|
||||
DB::statement('SET FOREIGN_KEY_CHECKS=0');
|
||||
|
||||
// Drop the foreign key constraint using raw SQL.
|
||||
DB::statement('ALTER TABLE '.$tablePrefix.'activities DROP FOREIGN KEY activities_user_id_foreign');
|
||||
|
||||
// Drop the index.
|
||||
DB::statement('ALTER TABLE '.$tablePrefix.'activities DROP INDEX activities_user_id_foreign');
|
||||
|
||||
// Change the column to be non-nullable.
|
||||
$table->unsignedInteger('user_id')->nullable(false)->change();
|
||||
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
|
||||
|
||||
// Re-enable foreign key checks.
|
||||
DB::statement('SET FOREIGN_KEY_CHECKS=1');
|
||||
});
|
||||
}
|
||||
};
|
||||
111
packages/Webkul/Activity/src/Models/Activity.php
Normal file
111
packages/Webkul/Activity/src/Models/Activity.php
Normal file
@@ -0,0 +1,111 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Activity\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Webkul\Activity\Contracts\Activity as ActivityContract;
|
||||
use Webkul\Contact\Models\PersonProxy;
|
||||
use Webkul\Lead\Models\LeadProxy;
|
||||
use Webkul\Product\Models\ProductProxy;
|
||||
use Webkul\User\Models\UserProxy;
|
||||
use Webkul\Warehouse\Models\WarehouseProxy;
|
||||
|
||||
class Activity extends Model implements ActivityContract
|
||||
{
|
||||
/**
|
||||
* Define table name of property
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'activities';
|
||||
|
||||
/**
|
||||
* Define relationships that should be touched on save
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $with = ['user'];
|
||||
|
||||
/**
|
||||
* Cast attributes to date time
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $casts = [
|
||||
'schedule_from' => 'datetime',
|
||||
'schedule_to' => 'datetime',
|
||||
];
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = [
|
||||
'title',
|
||||
'type',
|
||||
'location',
|
||||
'comment',
|
||||
'additional',
|
||||
'schedule_from',
|
||||
'schedule_to',
|
||||
'is_done',
|
||||
'user_id',
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the user that owns the activity.
|
||||
*/
|
||||
public function user()
|
||||
{
|
||||
return $this->belongsTo(UserProxy::modelClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* The participants that belong to the activity.
|
||||
*/
|
||||
public function participants()
|
||||
{
|
||||
return $this->hasMany(ParticipantProxy::modelClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the file associated with the activity.
|
||||
*/
|
||||
public function files()
|
||||
{
|
||||
return $this->hasMany(FileProxy::modelClass(), 'activity_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* The leads that belong to the activity.
|
||||
*/
|
||||
public function leads()
|
||||
{
|
||||
return $this->belongsToMany(LeadProxy::modelClass(), 'lead_activities');
|
||||
}
|
||||
|
||||
/**
|
||||
* The Person that belong to the activity.
|
||||
*/
|
||||
public function persons()
|
||||
{
|
||||
return $this->belongsToMany(PersonProxy::modelClass(), 'person_activities');
|
||||
}
|
||||
|
||||
/**
|
||||
* The leads that belong to the activity.
|
||||
*/
|
||||
public function products()
|
||||
{
|
||||
return $this->belongsToMany(ProductProxy::modelClass(), 'product_activities');
|
||||
}
|
||||
|
||||
/**
|
||||
* The Warehouse that belong to the activity.
|
||||
*/
|
||||
public function warehouses()
|
||||
{
|
||||
return $this->belongsToMany(WarehouseProxy::modelClass(), 'warehouse_activities');
|
||||
}
|
||||
}
|
||||
7
packages/Webkul/Activity/src/Models/ActivityProxy.php
Normal file
7
packages/Webkul/Activity/src/Models/ActivityProxy.php
Normal file
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Activity\Models;
|
||||
|
||||
use Konekt\Concord\Proxies\ModelProxy;
|
||||
|
||||
class ActivityProxy extends ModelProxy {}
|
||||
71
packages/Webkul/Activity/src/Models/File.php
Normal file
71
packages/Webkul/Activity/src/Models/File.php
Normal file
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Activity\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Webkul\Activity\Contracts\File as FileContract;
|
||||
|
||||
class File extends Model implements FileContract
|
||||
{
|
||||
/**
|
||||
* The table associated with the model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $table = 'activity_files';
|
||||
|
||||
/**
|
||||
* The attributes that should be appended to the model.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $appends = ['url'];
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = [
|
||||
'name',
|
||||
'path',
|
||||
'activity_id',
|
||||
];
|
||||
|
||||
/**
|
||||
* Get image url for the product image.
|
||||
*/
|
||||
public function url()
|
||||
{
|
||||
return Storage::url($this->path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get image url for the product image.
|
||||
*/
|
||||
public function getUrlAttribute()
|
||||
{
|
||||
return $this->url();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the activity that owns the file.
|
||||
*/
|
||||
public function activity()
|
||||
{
|
||||
return $this->belongsTo(ActivityProxy::modelClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function toArray()
|
||||
{
|
||||
$array = parent::toArray();
|
||||
|
||||
$array['url'] = $this->url;
|
||||
|
||||
return $array;
|
||||
}
|
||||
}
|
||||
7
packages/Webkul/Activity/src/Models/FileProxy.php
Normal file
7
packages/Webkul/Activity/src/Models/FileProxy.php
Normal file
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Activity\Models;
|
||||
|
||||
use Konekt\Concord\Proxies\ModelProxy;
|
||||
|
||||
class FileProxy extends ModelProxy {}
|
||||
52
packages/Webkul/Activity/src/Models/Participant.php
Normal file
52
packages/Webkul/Activity/src/Models/Participant.php
Normal file
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Activity\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Webkul\Activity\Contracts\Participant as ParticipantContract;
|
||||
use Webkul\Contact\Models\PersonProxy;
|
||||
use Webkul\User\Models\UserProxy;
|
||||
|
||||
class Participant extends Model implements ParticipantContract
|
||||
{
|
||||
public $timestamps = false;
|
||||
|
||||
protected $table = 'activity_participants';
|
||||
|
||||
protected $with = ['user', 'person'];
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = [
|
||||
'activity_id',
|
||||
'user_id',
|
||||
'person_id',
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the activity that owns the participant.
|
||||
*/
|
||||
public function activity()
|
||||
{
|
||||
return $this->belongsTo(ActivityProxy::modelClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the user that owns the participant.
|
||||
*/
|
||||
public function user()
|
||||
{
|
||||
return $this->belongsTo(UserProxy::modelClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the person that owns the participant.
|
||||
*/
|
||||
public function person()
|
||||
{
|
||||
return $this->belongsTo(PersonProxy::modelClass());
|
||||
}
|
||||
}
|
||||
7
packages/Webkul/Activity/src/Models/ParticipantProxy.php
Normal file
7
packages/Webkul/Activity/src/Models/ParticipantProxy.php
Normal file
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Activity\Models;
|
||||
|
||||
use Konekt\Concord\Proxies\ModelProxy;
|
||||
|
||||
class ParticipantProxy extends ModelProxy {}
|
||||
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Activity\Providers;
|
||||
|
||||
use Illuminate\Routing\Router;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
|
||||
class ActivityServiceProvider extends ServiceProvider
|
||||
{
|
||||
/**
|
||||
* Bootstrap services.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function boot(Router $router)
|
||||
{
|
||||
$this->loadMigrationsFrom(__DIR__.'/../Database/Migrations');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Activity\Providers;
|
||||
|
||||
use Webkul\Core\Providers\BaseModuleServiceProvider;
|
||||
|
||||
class ModuleServiceProvider extends BaseModuleServiceProvider
|
||||
{
|
||||
protected $models = [
|
||||
\Webkul\Activity\Models\Activity::class,
|
||||
\Webkul\Activity\Models\File::class,
|
||||
\Webkul\Activity\Models\Participant::class,
|
||||
];
|
||||
}
|
||||
187
packages/Webkul/Activity/src/Repositories/ActivityRepository.php
Executable file
187
packages/Webkul/Activity/src/Repositories/ActivityRepository.php
Executable file
@@ -0,0 +1,187 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Activity\Repositories;
|
||||
|
||||
use Illuminate\Container\Container;
|
||||
use Webkul\Core\Eloquent\Repository;
|
||||
|
||||
class ActivityRepository extends Repository
|
||||
{
|
||||
/**
|
||||
* Create a new repository instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(
|
||||
protected FileRepository $fileRepository,
|
||||
Container $container
|
||||
) {
|
||||
parent::__construct($container);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify Model class name
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function model()
|
||||
{
|
||||
return 'Webkul\Activity\Contracts\Activity';
|
||||
}
|
||||
|
||||
/**
|
||||
* Create pipeline.
|
||||
*
|
||||
* @return \Webkul\Activity\Contracts\Activity
|
||||
*/
|
||||
public function create(array $data)
|
||||
{
|
||||
$activity = parent::create($data);
|
||||
|
||||
if (isset($data['file'])) {
|
||||
$this->fileRepository->create([
|
||||
'name' => $data['name'] ?? $data['file']->getClientOriginalName(),
|
||||
'path' => $data['file']->store('activities/'.$activity->id),
|
||||
'activity_id' => $activity->id,
|
||||
]);
|
||||
}
|
||||
|
||||
if (! isset($data['participants'])) {
|
||||
return $activity;
|
||||
}
|
||||
|
||||
foreach ($data['participants']['users'] ?? [] as $userId) {
|
||||
$activity->participants()->create([
|
||||
'user_id' => $userId,
|
||||
]);
|
||||
}
|
||||
|
||||
foreach ($data['participants']['persons'] ?? [] as $personId) {
|
||||
$activity->participants()->create([
|
||||
'person_id' => $personId,
|
||||
]);
|
||||
}
|
||||
|
||||
return $activity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update pipeline.
|
||||
*
|
||||
* @param int $id
|
||||
* @param string $attribute
|
||||
* @return \Webkul\Activity\Contracts\Activity
|
||||
*/
|
||||
public function update(array $data, $id, $attribute = 'id')
|
||||
{
|
||||
$activity = parent::update($data, $id);
|
||||
|
||||
if (isset($data['participants'])) {
|
||||
$activity->participants()->delete();
|
||||
|
||||
foreach ($data['participants']['users'] ?? [] as $userId) {
|
||||
/**
|
||||
* In some cases, the component exists in an HTML form, and traditional HTML does not send an empty array.
|
||||
* Therefore, we need to check for an empty string.
|
||||
* This scenario occurs only when all participants are removed.
|
||||
*/
|
||||
if (empty($userId)) {
|
||||
break;
|
||||
}
|
||||
|
||||
$activity->participants()->create([
|
||||
'user_id' => $userId,
|
||||
]);
|
||||
}
|
||||
|
||||
foreach ($data['participants']['persons'] ?? [] as $personId) {
|
||||
/**
|
||||
* In some cases, the component exists in an HTML form, and traditional HTML does not send an empty array.
|
||||
* Therefore, we need to check for an empty string.
|
||||
* This scenario occurs only when all participants are removed.
|
||||
*/
|
||||
if (empty($personId)) {
|
||||
break;
|
||||
}
|
||||
|
||||
$activity->participants()->create([
|
||||
'person_id' => $personId,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
return $activity;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $dateRange
|
||||
* @return mixed
|
||||
*/
|
||||
public function getActivities($dateRange)
|
||||
{
|
||||
$tablePrefix = \DB::getTablePrefix();
|
||||
|
||||
return $this->select(
|
||||
'activities.id',
|
||||
'activities.created_at',
|
||||
'activities.title',
|
||||
'activities.schedule_from as start',
|
||||
'activities.schedule_to as end',
|
||||
'users.name as user_name',
|
||||
)
|
||||
->addSelect(\DB::raw('IF('.$tablePrefix.'activities.is_done, "done", "") as class'))
|
||||
->leftJoin('activity_participants', 'activities.id', '=', 'activity_participants.activity_id')
|
||||
->leftJoin('users', 'activities.user_id', '=', 'users.id')
|
||||
->whereIn('type', ['call', 'meeting', 'lunch'])
|
||||
->whereBetween('activities.schedule_from', $dateRange)
|
||||
->where(function ($query) {
|
||||
if ($userIds = bouncer()->getAuthorizedUserIds()) {
|
||||
$query->whereIn('activities.user_id', $userIds)
|
||||
->orWhereIn('activity_participants.user_id', $userIds);
|
||||
}
|
||||
})
|
||||
->distinct()
|
||||
->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $startFrom
|
||||
* @param string $endFrom
|
||||
* @param array $participants
|
||||
* @param int $id
|
||||
* @return bool
|
||||
*/
|
||||
public function isDurationOverlapping($startFrom, $endFrom, $participants, $id)
|
||||
{
|
||||
$queryBuilder = $this->leftJoin('activity_participants', 'activities.id', '=', 'activity_participants.activity_id')
|
||||
->where(function ($query) use ($startFrom, $endFrom) {
|
||||
$query->where([
|
||||
['activities.schedule_from', '<=', $startFrom],
|
||||
['activities.schedule_to', '>=', $startFrom],
|
||||
])->orWhere([
|
||||
['activities.schedule_from', '>=', $startFrom],
|
||||
['activities.schedule_from', '<=', $endFrom],
|
||||
]);
|
||||
})
|
||||
->where(function ($query) use ($participants) {
|
||||
if (is_null($participants)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isset($participants['users'])) {
|
||||
$query->orWhereIn('activity_participants.user_id', $participants['users']);
|
||||
}
|
||||
|
||||
if (isset($participants['persons'])) {
|
||||
$query->orWhereIn('activity_participants.person_id', $participants['persons']);
|
||||
}
|
||||
})
|
||||
->groupBy('activities.id');
|
||||
|
||||
if (! is_null($id)) {
|
||||
$queryBuilder->where('activities.id', '!=', $id);
|
||||
}
|
||||
|
||||
return $queryBuilder->count() ? true : false;
|
||||
}
|
||||
}
|
||||
18
packages/Webkul/Activity/src/Repositories/FileRepository.php
Executable file
18
packages/Webkul/Activity/src/Repositories/FileRepository.php
Executable file
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Activity\Repositories;
|
||||
|
||||
use Webkul\Core\Eloquent\Repository;
|
||||
|
||||
class FileRepository extends Repository
|
||||
{
|
||||
/**
|
||||
* Specify model class name.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function model()
|
||||
{
|
||||
return \Webkul\Activity\Contracts\File::class;
|
||||
}
|
||||
}
|
||||
18
packages/Webkul/Activity/src/Repositories/ParticipantRepository.php
Executable file
18
packages/Webkul/Activity/src/Repositories/ParticipantRepository.php
Executable file
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Activity\Repositories;
|
||||
|
||||
use Webkul\Core\Eloquent\Repository;
|
||||
|
||||
class ParticipantRepository extends Repository
|
||||
{
|
||||
/**
|
||||
* Specify Model class name
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function model()
|
||||
{
|
||||
return 'Webkul\Activity\Contracts\Participant';
|
||||
}
|
||||
}
|
||||
183
packages/Webkul/Activity/src/Traits/LogsActivity.php
Normal file
183
packages/Webkul/Activity/src/Traits/LogsActivity.php
Normal file
@@ -0,0 +1,183 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Activity\Traits;
|
||||
|
||||
use Webkul\Activity\Repositories\ActivityRepository;
|
||||
use Webkul\Attribute\Contracts\AttributeValue;
|
||||
use Webkul\Attribute\Repositories\AttributeValueRepository;
|
||||
|
||||
trait LogsActivity
|
||||
{
|
||||
/**
|
||||
* The "booted" method of the model.
|
||||
*/
|
||||
protected static function booted(): void
|
||||
{
|
||||
static::created(function ($model) {
|
||||
if (! method_exists($model->entity ?? $model, 'activities')) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (! $model instanceof AttributeValue) {
|
||||
$activity = app(ActivityRepository::class)->create([
|
||||
'type' => 'system',
|
||||
'title' => trans('admin::app.activities.created'),
|
||||
'is_done' => 1,
|
||||
'user_id' => auth()->check()
|
||||
? auth()->id()
|
||||
: null,
|
||||
]);
|
||||
|
||||
$model->activities()->attach($activity->id);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static::logActivity($model);
|
||||
});
|
||||
|
||||
static::updated(function ($model) {
|
||||
if (! method_exists($model->entity ?? $model, 'activities')) {
|
||||
return;
|
||||
}
|
||||
|
||||
static::logActivity($model);
|
||||
});
|
||||
|
||||
static::deleting(function ($model) {
|
||||
if (! method_exists($model->entity ?? $model, 'activities')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$model->activities()->delete();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Create activity.
|
||||
*/
|
||||
protected static function logActivity($model)
|
||||
{
|
||||
$customAttributes = [];
|
||||
|
||||
if (method_exists($model, 'getCustomAttributes')) {
|
||||
$customAttributes = $model->getCustomAttributes()->pluck('code')->toArray();
|
||||
}
|
||||
|
||||
$updatedAttributes = static::getUpdatedAttributes($model);
|
||||
|
||||
foreach ($updatedAttributes as $attributeCode => $attributeData) {
|
||||
if (in_array($attributeCode, $customAttributes)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$attributeCode = $model->attribute?->name ?: $attributeCode;
|
||||
|
||||
$activity = app(ActivityRepository::class)->create([
|
||||
'type' => 'system',
|
||||
'title' => trans('admin::app.activities.updated', ['attribute' => $attributeCode]),
|
||||
'is_done' => 1,
|
||||
'additional' => json_encode([
|
||||
'attribute' => $attributeCode,
|
||||
'new' => [
|
||||
'value' => $attributeData['new'],
|
||||
'label' => static::getAttributeLabel($attributeData['new'], $model->attribute),
|
||||
],
|
||||
'old' => [
|
||||
'value' => $attributeData['old'],
|
||||
'label' => static::getAttributeLabel($attributeData['old'], $model->attribute),
|
||||
],
|
||||
]),
|
||||
'user_id' => auth()->id(),
|
||||
]);
|
||||
|
||||
if ($model instanceof AttributeValue) {
|
||||
$model->entity->activities()->attach($activity->id);
|
||||
} else {
|
||||
$model->activities()->attach($activity->id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get attribute label.
|
||||
*/
|
||||
protected static function getAttributeLabel($value, $attribute)
|
||||
{
|
||||
return app(AttributeValueRepository::class)->getAttributeLabel($value, $attribute);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create activity.
|
||||
*/
|
||||
protected static function getUpdatedAttributes($model)
|
||||
{
|
||||
$updatedAttributes = [];
|
||||
|
||||
foreach ($model->getDirty() as $key => $value) {
|
||||
if (in_array($key, [
|
||||
'id',
|
||||
'attribute_id',
|
||||
'entity_id',
|
||||
'entity_type',
|
||||
'updated_at',
|
||||
])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$newValue = static::decodeValueIfJson($value);
|
||||
|
||||
$oldValue = static::decodeValueIfJson($model->getOriginal($key));
|
||||
|
||||
if ($newValue != $oldValue) {
|
||||
$updatedAttributes[$key] = [
|
||||
'new' => $newValue,
|
||||
'old' => $oldValue,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return $updatedAttributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert value if json.
|
||||
*/
|
||||
protected static function decodeValueIfJson($value)
|
||||
{
|
||||
if (
|
||||
! is_array($value)
|
||||
&& json_decode($value, true)
|
||||
) {
|
||||
$value = json_decode($value, true);
|
||||
}
|
||||
|
||||
if (! is_array($value)) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
static::ksortRecursive($value);
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort array recursively.
|
||||
*/
|
||||
protected static function ksortRecursive(&$array)
|
||||
{
|
||||
if (! is_array($array)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ksort($array);
|
||||
|
||||
foreach ($array as &$value) {
|
||||
if (! is_array($value)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
static::ksortRecursive($value);
|
||||
}
|
||||
}
|
||||
}
|
||||
5
packages/Webkul/Admin/.gitignore
vendored
Executable file
5
packages/Webkul/Admin/.gitignore
vendored
Executable file
@@ -0,0 +1,5 @@
|
||||
/node_modules
|
||||
/package-lock.json
|
||||
npm-debug.log
|
||||
/playwright-report
|
||||
/test-results
|
||||
35
packages/Webkul/Admin/composer.json
Executable file
35
packages/Webkul/Admin/composer.json
Executable file
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"name": "krayin/laravel-admin",
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Jitendra Singh",
|
||||
"email": "jitendra@webkul.com"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"krayin/laravel-attribute": "^1.0",
|
||||
"krayin/laravel-contact": "^1.0",
|
||||
"krayin/laravel-core": "^1.0",
|
||||
"krayin/laravel-email": "^1.0",
|
||||
"krayin/laravel-lead": "^1.0",
|
||||
"krayin/laravel-product": "^1.0",
|
||||
"krayin/laravel-tag": "^1.0",
|
||||
"krayin/laravel-ui": "^1.0",
|
||||
"krayin/laravel-user": "^1.0"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Webkul\\Admin\\": "src/"
|
||||
}
|
||||
},
|
||||
"extra": {
|
||||
"laravel": {
|
||||
"providers": [
|
||||
"Webkul\\Admin\\Providers\\AdminServiceProvider"
|
||||
],
|
||||
"aliases": {}
|
||||
}
|
||||
},
|
||||
"minimum-stability": "dev"
|
||||
}
|
||||
35
packages/Webkul/Admin/package.json
Normal file
35
packages/Webkul/Admin/package.json
Normal file
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vite build"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@playwright/test": "^1.50.1",
|
||||
"@types/node": "^22.7.8",
|
||||
"autoprefixer": "^10.4.16",
|
||||
"axios": "^1.7.4",
|
||||
"laravel-vite-plugin": "^1.0",
|
||||
"postcss": "^8.4.23",
|
||||
"tailwindcss": "^3.3.2",
|
||||
"vite": "^5.4.12",
|
||||
"vue": "^3.4.21"
|
||||
},
|
||||
"dependencies": {
|
||||
"@vee-validate/i18n": "^4.9.1",
|
||||
"@vee-validate/rules": "^4.9.1",
|
||||
"@vitejs/plugin-vue": "^4.2.3",
|
||||
"chartjs-chart-funnel": "^4.2.1",
|
||||
"dompurify": "^3.1.7",
|
||||
"dotenv": "^16.4.7",
|
||||
"flatpickr": "^4.6.13",
|
||||
"mitt": "^3.0.1",
|
||||
"playwright": "^1.48.1",
|
||||
"readline-sync": "^1.4.10",
|
||||
"vee-validate": "^4.9.1",
|
||||
"vue-cal": "^4.9.0",
|
||||
"vue-flatpickr": "^2.3.0",
|
||||
"vuedraggable": "^4.1.0"
|
||||
}
|
||||
}
|
||||
3
packages/Webkul/Admin/postcss.config.cjs
Normal file
3
packages/Webkul/Admin/postcss.config.cjs
Normal file
@@ -0,0 +1,3 @@
|
||||
module.exports = ({ env }) => ({
|
||||
plugins: [require("tailwindcss")(), require("autoprefixer")()],
|
||||
});
|
||||
60
packages/Webkul/Admin/src/Bouncer.php
Executable file
60
packages/Webkul/Admin/src/Bouncer.php
Executable file
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Admin;
|
||||
|
||||
use Webkul\User\Repositories\UserRepository;
|
||||
|
||||
class Bouncer
|
||||
{
|
||||
/**
|
||||
* Checks if user allowed or not for certain action
|
||||
*
|
||||
* @param string $permission
|
||||
* @return void
|
||||
*/
|
||||
public function hasPermission($permission)
|
||||
{
|
||||
if (auth()->guard('user')->check() && auth()->guard('user')->user()->role->permission_type == 'all') {
|
||||
return true;
|
||||
} else {
|
||||
if (! auth()->guard('user')->check() || ! auth()->guard('user')->user()->hasPermission($permission)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if user allowed or not for certain action
|
||||
*
|
||||
* @param string $permission
|
||||
* @return void
|
||||
*/
|
||||
public static function allow($permission)
|
||||
{
|
||||
if (! auth()->guard('user')->check() || ! auth()->guard('user')->user()->hasPermission($permission)) {
|
||||
abort(401, 'This action is unauthorized');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will return user ids of current user's groups
|
||||
*
|
||||
* @return array|null
|
||||
*/
|
||||
public function getAuthorizedUserIds()
|
||||
{
|
||||
$user = auth()->guard('user')->user();
|
||||
|
||||
if ($user->view_permission == 'global') {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($user->view_permission == 'group') {
|
||||
return app(UserRepository::class)->getCurrentUserGroupsUserIds();
|
||||
} else {
|
||||
return [$user->id];
|
||||
}
|
||||
}
|
||||
}
|
||||
527
packages/Webkul/Admin/src/Config/acl.php
Normal file
527
packages/Webkul/Admin/src/Config/acl.php
Normal file
@@ -0,0 +1,527 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
[
|
||||
'key' => 'dashboard',
|
||||
'name' => 'admin::app.layouts.dashboard',
|
||||
'route' => 'admin.dashboard.index',
|
||||
'sort' => 1,
|
||||
], [
|
||||
'key' => 'leads',
|
||||
'name' => 'admin::app.acl.leads',
|
||||
'route' => 'admin.leads.index',
|
||||
'sort' => 2,
|
||||
], [
|
||||
'key' => 'leads.create',
|
||||
'name' => 'admin::app.acl.create',
|
||||
'route' => ['admin.leads.create', 'admin.leads.store'],
|
||||
'sort' => 1,
|
||||
], [
|
||||
'key' => 'leads.view',
|
||||
'name' => 'admin::app.acl.view',
|
||||
'route' => 'admin.leads.view',
|
||||
'sort' => 2,
|
||||
], [
|
||||
'key' => 'leads.edit',
|
||||
'name' => 'admin::app.acl.edit',
|
||||
'route' => ['admin.leads.edit', 'admin.leads.update', 'admin.leads.mass_update'],
|
||||
'sort' => 3,
|
||||
], [
|
||||
'key' => 'leads.delete',
|
||||
'name' => 'admin::app.acl.delete',
|
||||
'route' => ['admin.leads.delete', 'admin.leads.mass_delete'],
|
||||
'sort' => 4,
|
||||
], [
|
||||
'key' => 'quotes',
|
||||
'name' => 'admin::app.acl.quotes',
|
||||
'route' => 'admin.quotes.index',
|
||||
'sort' => 3,
|
||||
], [
|
||||
'key' => 'quotes.create',
|
||||
'name' => 'admin::app.acl.create',
|
||||
'route' => ['admin.quotes.create', 'admin.quotes.store'],
|
||||
'sort' => 1,
|
||||
], [
|
||||
'key' => 'quotes.edit',
|
||||
'name' => 'admin::app.acl.edit',
|
||||
'route' => ['admin.quotes.edit', 'admin.quotes.update'],
|
||||
'sort' => 2,
|
||||
], [
|
||||
'key' => 'quotes.print',
|
||||
'name' => 'admin::app.acl.print',
|
||||
'route' => 'admin.quotes.print',
|
||||
'sort' => 3,
|
||||
], [
|
||||
'key' => 'quotes.delete',
|
||||
'name' => 'admin::app.acl.delete',
|
||||
'route' => ['admin.quotes.delete', 'admin.quotes.mass_delete'],
|
||||
'sort' => 4,
|
||||
], [
|
||||
'key' => 'mail',
|
||||
'name' => 'admin::app.acl.mail',
|
||||
'route' => 'admin.mail.index',
|
||||
'sort' => 4,
|
||||
], [
|
||||
'key' => 'mail.inbox',
|
||||
'name' => 'admin::app.acl.inbox',
|
||||
'route' => 'admin.mail.index',
|
||||
'sort' => 1,
|
||||
], [
|
||||
'key' => 'mail.draft',
|
||||
'name' => 'admin::app.acl.draft',
|
||||
'route' => 'admin.mail.index',
|
||||
'sort' => 2,
|
||||
], [
|
||||
'key' => 'mail.outbox',
|
||||
'name' => 'admin::app.acl.outbox',
|
||||
'route' => 'admin.mail.index',
|
||||
'sort' => 3,
|
||||
], [
|
||||
'key' => 'mail.sent',
|
||||
'name' => 'admin::app.acl.sent',
|
||||
'route' => 'admin.mail.index',
|
||||
'sort' => 4,
|
||||
], [
|
||||
'key' => 'mail.trash',
|
||||
'name' => 'admin::app.acl.trash',
|
||||
'route' => 'admin.mail.index',
|
||||
'sort' => 5,
|
||||
], [
|
||||
'key' => 'mail.compose',
|
||||
'name' => 'admin::app.acl.create',
|
||||
'route' => ['admin.mail.store'],
|
||||
'sort' => 6,
|
||||
], [
|
||||
'key' => 'mail.view',
|
||||
'name' => 'admin::app.acl.view',
|
||||
'route' => 'admin.mail.view',
|
||||
'sort' => 7,
|
||||
], [
|
||||
'key' => 'mail.edit',
|
||||
'name' => 'admin::app.acl.edit',
|
||||
'route' => 'admin.mail.update',
|
||||
'sort' => 8,
|
||||
], [
|
||||
'key' => 'mail.delete',
|
||||
'name' => 'admin::app.acl.delete',
|
||||
'route' => ['admin.mail.delete', 'admin.mail.mass_delete'],
|
||||
'sort' => 9,
|
||||
], [
|
||||
'key' => 'activities',
|
||||
'name' => 'admin::app.acl.activities',
|
||||
'route' => 'admin.activities.index',
|
||||
'sort' => 5,
|
||||
], [
|
||||
'key' => 'activities.create',
|
||||
'name' => 'admin::app.acl.create',
|
||||
'route' => ['admin.activities.create', 'admin.activities.store'],
|
||||
'sort' => 1,
|
||||
], [
|
||||
'key' => 'activities.edit',
|
||||
'name' => 'admin::app.acl.edit',
|
||||
'route' => ['admin.activities.edit', 'admin.activities.update', 'admin.activities.mass_update'],
|
||||
'sort' => 2,
|
||||
], [
|
||||
'key' => 'activities.delete',
|
||||
'name' => 'admin::app.acl.delete',
|
||||
'route' => ['admin.activities.delete', 'admin.activities.mass_delete'],
|
||||
'sort' => 3,
|
||||
], [
|
||||
'key' => 'contacts',
|
||||
'name' => 'admin::app.acl.contacts',
|
||||
'route' => 'admin.contacts.users.index',
|
||||
'sort' => 6,
|
||||
], [
|
||||
'key' => 'contacts.persons',
|
||||
'name' => 'admin::app.acl.persons',
|
||||
'route' => 'admin.contacts.persons.index',
|
||||
'sort' => 1,
|
||||
], [
|
||||
'key' => 'contacts.persons.create',
|
||||
'name' => 'admin::app.acl.create',
|
||||
'route' => ['admin.contacts.persons.create', 'admin.contacts.persons.store'],
|
||||
'sort' => 2,
|
||||
], [
|
||||
'key' => 'contacts.persons.edit',
|
||||
'name' => 'admin::app.acl.edit',
|
||||
'route' => ['admin.contacts.persons.edit', 'admin.contacts.persons.update'],
|
||||
'sort' => 3,
|
||||
], [
|
||||
'key' => 'contacts.persons.delete',
|
||||
'name' => 'admin::app.acl.delete',
|
||||
'route' => ['admin.contacts.persons.delete', 'admin.contacts.persons.mass_delete'],
|
||||
'sort' => 4,
|
||||
], [
|
||||
'key' => 'contacts.persons.view',
|
||||
'name' => 'admin::app.acl.view',
|
||||
'route' => 'admin.contacts.persons.view',
|
||||
'sort' => 5,
|
||||
], [
|
||||
'key' => 'contacts.organizations',
|
||||
'name' => 'admin::app.acl.organizations',
|
||||
'route' => 'admin.contacts.organizations.index',
|
||||
'sort' => 2,
|
||||
], [
|
||||
'key' => 'contacts.organizations.create',
|
||||
'name' => 'admin::app.acl.create',
|
||||
'route' => ['admin.contacts.organizations.create', 'admin.contacts.organizations.store'],
|
||||
'sort' => 1,
|
||||
], [
|
||||
'key' => 'contacts.organizations.edit',
|
||||
'name' => 'admin::app.acl.edit',
|
||||
'route' => ['admin.contacts.organizations.edit', 'admin.contacts.organizations.update'],
|
||||
'sort' => 2,
|
||||
], [
|
||||
'key' => 'contacts.organizations.delete',
|
||||
'name' => 'admin::app.acl.delete',
|
||||
'route' => ['admin.contacts.organizations.delete', 'admin.contacts.organizations.mass_delete'],
|
||||
'sort' => 3,
|
||||
], [
|
||||
'key' => 'products',
|
||||
'name' => 'admin::app.acl.products',
|
||||
'route' => 'admin.products.index',
|
||||
'sort' => 7,
|
||||
], [
|
||||
'key' => 'products.create',
|
||||
'name' => 'admin::app.acl.create',
|
||||
'route' => ['admin.products.create', 'admin.products.store'],
|
||||
'sort' => 1,
|
||||
], [
|
||||
'key' => 'products.edit',
|
||||
'name' => 'admin::app.acl.edit',
|
||||
'route' => ['admin.products.edit', 'admin.products.update'],
|
||||
'sort' => 2,
|
||||
], [
|
||||
'key' => 'products.delete',
|
||||
'name' => 'admin::app.acl.delete',
|
||||
'route' => ['admin.products.delete', 'admin.products.mass_delete'],
|
||||
'sort' => 3,
|
||||
], [
|
||||
'key' => 'products.view',
|
||||
'name' => 'admin::app.acl.view',
|
||||
'route' => 'admin.products.view',
|
||||
'sort' => 3,
|
||||
], [
|
||||
'key' => 'settings',
|
||||
'name' => 'admin::app.acl.settings',
|
||||
'route' => 'admin.settings.index',
|
||||
'sort' => 8,
|
||||
], [
|
||||
'key' => 'settings.user',
|
||||
'name' => 'admin::app.acl.user',
|
||||
'route' => ['admin.settings.groups.index', 'admin.settings.roles.index', 'admin.settings.users.index'],
|
||||
'sort' => 1,
|
||||
], [
|
||||
'key' => 'settings.user.groups',
|
||||
'name' => 'admin::app.acl.groups',
|
||||
'route' => 'admin.settings.groups.index',
|
||||
'sort' => 1,
|
||||
], [
|
||||
'key' => 'settings.user.groups.create',
|
||||
'name' => 'admin::app.acl.create',
|
||||
'route' => ['admin.settings.groups.create', 'admin.settings.groups.store'],
|
||||
'sort' => 1,
|
||||
], [
|
||||
'key' => 'settings.user.groups.edit',
|
||||
'name' => 'admin::app.acl.edit',
|
||||
'route' => ['admin.settings.groups.edit', 'admin.settings.groups.update'],
|
||||
'sort' => 2,
|
||||
], [
|
||||
'key' => 'settings.user.groups.delete',
|
||||
'name' => 'admin::app.acl.delete',
|
||||
'route' => 'admin.settings.groups.delete',
|
||||
'sort' => 3,
|
||||
], [
|
||||
'key' => 'settings.user.roles',
|
||||
'name' => 'admin::app.acl.roles',
|
||||
'route' => 'admin.settings.roles.index',
|
||||
'sort' => 2,
|
||||
], [
|
||||
'key' => 'settings.user.roles.create',
|
||||
'name' => 'admin::app.acl.create',
|
||||
'route' => ['admin.settings.roles.create', 'admin.settings.roles.store'],
|
||||
'sort' => 1,
|
||||
], [
|
||||
'key' => 'settings.user.roles.edit',
|
||||
'name' => 'admin::app.acl.edit',
|
||||
'route' => ['admin.settings.roles.edit', 'admin.settings.roles.update'],
|
||||
'sort' => 2,
|
||||
], [
|
||||
'key' => 'settings.user.roles.delete',
|
||||
'name' => 'admin::app.acl.delete',
|
||||
'route' => 'admin.settings.roles.delete',
|
||||
'sort' => 3,
|
||||
], [
|
||||
'key' => 'settings.user.users',
|
||||
'name' => 'admin::app.acl.users',
|
||||
'route' => 'admin.settings.users.index',
|
||||
'sort' => 3,
|
||||
], [
|
||||
'key' => 'settings.user.users.create',
|
||||
'name' => 'admin::app.acl.create',
|
||||
'route' => ['admin.settings.users.create', 'admin.settings.users.store'],
|
||||
'sort' => 1,
|
||||
], [
|
||||
'key' => 'settings.user.users.edit',
|
||||
'name' => 'admin::app.acl.edit',
|
||||
'route' => ['admin.settings.users.edit', 'admin.settings.users.update', 'admin.settings.users.mass_update'],
|
||||
'sort' => 2,
|
||||
], [
|
||||
'key' => 'settings.user.users.delete',
|
||||
'name' => 'admin::app.acl.delete',
|
||||
'route' => ['admin.settings.users.delete', 'admin.settings.users.mass_delete'],
|
||||
'sort' => 3,
|
||||
], [
|
||||
'key' => 'settings.lead',
|
||||
'name' => 'admin::app.acl.lead',
|
||||
'route' => ['admin.settings.pipelines.index', 'admin.settings.sources.index', 'admin.settings.types.index'],
|
||||
'sort' => 2,
|
||||
], [
|
||||
'key' => 'settings.lead.pipelines',
|
||||
'name' => 'admin::app.acl.pipelines',
|
||||
'route' => 'admin.settings.pipelines.index',
|
||||
'sort' => 1,
|
||||
], [
|
||||
'key' => 'settings.lead.pipelines.create',
|
||||
'name' => 'admin::app.acl.create',
|
||||
'route' => ['admin.settings.pipelines.create', 'admin.settings.pipelines.store'],
|
||||
'sort' => 1,
|
||||
], [
|
||||
'key' => 'settings.lead.pipelines.edit',
|
||||
'name' => 'admin::app.acl.edit',
|
||||
'route' => ['admin.settings.pipelines.edit', 'admin.settings.pipelines.update'],
|
||||
'sort' => 2,
|
||||
], [
|
||||
'key' => 'settings.lead.pipelines.delete',
|
||||
'name' => 'admin::app.acl.delete',
|
||||
'route' => 'admin.settings.pipelines.delete',
|
||||
'sort' => 3,
|
||||
], [
|
||||
'key' => 'settings.lead.sources',
|
||||
'name' => 'admin::app.acl.sources',
|
||||
'route' => 'admin.settings.sources.index',
|
||||
'sort' => 2,
|
||||
], [
|
||||
'key' => 'settings.lead.sources.create',
|
||||
'name' => 'admin::app.acl.create',
|
||||
'route' => ['admin.settings.sources.store'],
|
||||
'sort' => 1,
|
||||
], [
|
||||
'key' => 'settings.lead.sources.edit',
|
||||
'name' => 'admin::app.acl.edit',
|
||||
'route' => ['admin.settings.sources.edit', 'admin.settings.sources.update'],
|
||||
'sort' => 2,
|
||||
], [
|
||||
'key' => 'settings.lead.sources.delete',
|
||||
'name' => 'admin::app.acl.delete',
|
||||
'route' => 'admin.settings.sources.delete',
|
||||
'sort' => 3,
|
||||
], [
|
||||
'key' => 'settings.lead.types',
|
||||
'name' => 'admin::app.acl.types',
|
||||
'route' => 'admin.settings.types.index',
|
||||
'sort' => 3,
|
||||
], [
|
||||
'key' => 'settings.lead.types.create',
|
||||
'name' => 'admin::app.acl.create',
|
||||
'route' => ['admin.settings.types.store'],
|
||||
'sort' => 1,
|
||||
], [
|
||||
'key' => 'settings.lead.types.edit',
|
||||
'name' => 'admin::app.acl.edit',
|
||||
'route' => ['admin.settings.types.edit', 'admin.settings.types.update'],
|
||||
'sort' => 2,
|
||||
], [
|
||||
'key' => 'settings.lead.types.delete',
|
||||
'name' => 'admin::app.acl.delete',
|
||||
'route' => 'admin.settings.types.delete',
|
||||
'sort' => 3,
|
||||
], [
|
||||
'key' => 'settings.automation',
|
||||
'name' => 'admin::app.acl.automation',
|
||||
'route' => ['admin.settings.attributes.index', 'admin.settings.email_templates.index', 'admin.settings.workflows.index'],
|
||||
'sort' => 3,
|
||||
], [
|
||||
'key' => 'settings.automation.attributes',
|
||||
'name' => 'admin::app.acl.attributes',
|
||||
'route' => 'admin.settings.attributes.index',
|
||||
'sort' => 1,
|
||||
], [
|
||||
'key' => 'settings.automation.attributes.create',
|
||||
'name' => 'admin::app.acl.create',
|
||||
'route' => ['admin.settings.attributes.create', 'admin.settings.attributes.store'],
|
||||
'sort' => 1,
|
||||
], [
|
||||
'key' => 'settings.automation.attributes.edit',
|
||||
'name' => 'admin::app.acl.edit',
|
||||
'route' => ['admin.settings.attributes.edit', 'admin.settings.attributes.update', 'admin.settings.attributes.mass_update'],
|
||||
'sort' => 2,
|
||||
], [
|
||||
'key' => 'settings.automation.attributes.delete',
|
||||
'name' => 'admin::app.acl.delete',
|
||||
'route' => 'admin.settings.attributes.delete',
|
||||
'sort' => 3,
|
||||
], [
|
||||
'key' => 'settings.automation.email_templates',
|
||||
'name' => 'admin::app.acl.email-templates',
|
||||
'route' => 'admin.settings.email_templates.index',
|
||||
'sort' => 7,
|
||||
], [
|
||||
'key' => 'settings.automation.email_templates.create',
|
||||
'name' => 'admin::app.acl.create',
|
||||
'route' => ['admin.settings.email_templates.create', 'admin.settings.email_templates.store'],
|
||||
'sort' => 1,
|
||||
], [
|
||||
'key' => 'settings.automation.email_templates.edit',
|
||||
'name' => 'admin::app.acl.edit',
|
||||
'route' => ['admin.settings.email_templates.edit', 'admin.settings.email_templates.update'],
|
||||
'sort' => 2,
|
||||
], [
|
||||
'key' => 'settings.automation.email_templates.delete',
|
||||
'name' => 'admin::app.acl.delete',
|
||||
'route' => 'admin.settings.email_templates.delete',
|
||||
'sort' => 3,
|
||||
], [
|
||||
'key' => 'settings.automation.workflows',
|
||||
'name' => 'admin::app.acl.workflows',
|
||||
'route' => 'admin.settings.workflows.index',
|
||||
'sort' => 2,
|
||||
], [
|
||||
'key' => 'settings.automation.workflows.create',
|
||||
'name' => 'admin::app.acl.create',
|
||||
'route' => ['admin.settings.workflows.create', 'admin.settings.workflows.store'],
|
||||
'sort' => 1,
|
||||
], [
|
||||
'key' => 'settings.automation.workflows.edit',
|
||||
'name' => 'admin::app.acl.edit',
|
||||
'route' => ['admin.settings.workflows.edit', 'admin.settings.workflows.update'],
|
||||
'sort' => 2,
|
||||
], [
|
||||
'key' => 'settings.automation.workflows.delete',
|
||||
'name' => 'admin::app.acl.delete',
|
||||
'route' => 'admin.settings.workflows.delete',
|
||||
'sort' => 3,
|
||||
], [
|
||||
'key' => 'settings.automation.events',
|
||||
'name' => 'admin::app.acl.event',
|
||||
'route' => 'admin.settings.marketing.events.index',
|
||||
'sort' => 2,
|
||||
], [
|
||||
'key' => 'settings.automation.events.create',
|
||||
'name' => 'admin::app.acl.create',
|
||||
'route' => ['admin.settings.marketing.events.create', 'admin.settings.marketing.events.store'],
|
||||
'sort' => 1,
|
||||
], [
|
||||
'key' => 'settings.automation.events.edit',
|
||||
'name' => 'admin::app.acl.edit',
|
||||
'route' => ['admin.settings.marketing.events.edit', 'admin.settings.marketing.events.update'],
|
||||
'sort' => 2,
|
||||
], [
|
||||
'key' => 'settings.automation.events.delete',
|
||||
'name' => 'admin::app.acl.delete',
|
||||
'route' => ['admin.settings.marketing.events.delete', 'admin.settings.marketing.events.mass_delete'],
|
||||
'sort' => 3,
|
||||
], [
|
||||
'key' => 'settings.automation.campaigns',
|
||||
'name' => 'admin::app.acl.campaigns',
|
||||
'route' => 'admin.settings.marketing.campaigns.index',
|
||||
'sort' => 2,
|
||||
], [
|
||||
'key' => 'settings.automation.campaigns.create',
|
||||
'name' => 'admin::app.acl.create',
|
||||
'route' => ['admin.settings.marketing.campaigns.create', 'admin.settings.marketing.campaigns.store'],
|
||||
'sort' => 1,
|
||||
], [
|
||||
'key' => 'settings.automation.campaigns.edit',
|
||||
'name' => 'admin::app.acl.edit',
|
||||
'route' => ['admin.settings.marketing.campaigns.edit', 'admin.settings.marketing.campaigns.update'],
|
||||
'sort' => 2,
|
||||
], [
|
||||
'key' => 'settings.automation.campaigns.delete',
|
||||
'name' => 'admin::app.acl.delete',
|
||||
'route' => ['admin.settings.marketing.campaigns.delete', 'admin.settings.marketing.campaigns.mass_delete'],
|
||||
'sort' => 3,
|
||||
], [
|
||||
'key' => 'settings.automation.webhooks',
|
||||
'name' => 'admin::app.acl.webhook',
|
||||
'route' => 'admin.settings.webhooks.index',
|
||||
'sort' => 1,
|
||||
], [
|
||||
'key' => 'settings.automation.webhooks.create',
|
||||
'name' => 'admin::app.acl.create',
|
||||
'route' => ['admin.settings.webhooks.create', 'admin.settings.webhooks.store'],
|
||||
'sort' => 1,
|
||||
], [
|
||||
'key' => 'settings.automation.webhooks.edit',
|
||||
'name' => 'admin::app.acl.edit',
|
||||
'route' => ['admin.settings.webhooks.edit', 'admin.settings.webhooks.update'],
|
||||
'sort' => 2,
|
||||
], [
|
||||
'key' => 'settings.automation.webhooks.delete',
|
||||
'name' => 'admin::app.acl.delete',
|
||||
'route' => 'admin.settings.webhooks.delete',
|
||||
'sort' => 3,
|
||||
], [
|
||||
'key' => 'settings.other_settings',
|
||||
'name' => 'admin::app.acl.other-settings',
|
||||
'route' => 'admin.settings.tags.index',
|
||||
'sort' => 4,
|
||||
], [
|
||||
'key' => 'settings.other_settings.tags',
|
||||
'name' => 'admin::app.acl.tags',
|
||||
'route' => 'admin.settings.tags.index',
|
||||
'sort' => 1,
|
||||
], [
|
||||
'key' => 'settings.other_settings.tags.create',
|
||||
'name' => 'admin::app.acl.create',
|
||||
'route' => ['admin.settings.tags.create', 'admin.settings.tags.store', 'admin.leads.tags.attach'],
|
||||
'sort' => 1,
|
||||
], [
|
||||
'key' => 'settings.other_settings.tags.edit',
|
||||
'name' => 'admin::app.acl.edit',
|
||||
'route' => ['admin.settings.tags.edit', 'admin.settings.tags.update'],
|
||||
'sort' => 1,
|
||||
], [
|
||||
'key' => 'settings.other_settings.tags.delete',
|
||||
'name' => 'admin::app.acl.delete',
|
||||
'route' => ['admin.settings.tags.delete', 'admin.settings.tags.mass_delete', 'admin.leads.tags.detach'],
|
||||
'sort' => 2,
|
||||
],
|
||||
[
|
||||
'key' => 'settings.data_transfer',
|
||||
'name' => 'admin::app.acl.data-transfer',
|
||||
'route' => 'admin.settings.data_transfer.imports.index',
|
||||
'sort' => 10,
|
||||
], [
|
||||
'key' => 'settings.data_transfer.imports',
|
||||
'name' => 'admin::app.acl.imports',
|
||||
'route' => 'admin.settings.data_transfer.imports.index',
|
||||
'sort' => 1,
|
||||
], [
|
||||
'key' => 'settings.data_transfer.imports.create',
|
||||
'name' => 'admin::app.acl.create',
|
||||
'route' => 'admin.settings.data_transfer.imports.create',
|
||||
'sort' => 1,
|
||||
], [
|
||||
'key' => 'settings.data_transfer.imports.edit',
|
||||
'name' => 'admin::app.acl.edit',
|
||||
'route' => 'admin.settings.data_transfer.imports.edit',
|
||||
'sort' => 2,
|
||||
], [
|
||||
'key' => 'settings.data_transfer.imports.delete',
|
||||
'name' => 'admin::app.acl.delete',
|
||||
'route' => 'admin.settings.data_transfer.imports.delete',
|
||||
'sort' => 3,
|
||||
], [
|
||||
'key' => 'settings.data_transfer.imports.import',
|
||||
'name' => 'admin::app.acl.import',
|
||||
'route' => 'admin.settings.data_transfer.imports.imports',
|
||||
'sort' => 4,
|
||||
],
|
||||
[
|
||||
'key' => 'configuration',
|
||||
'name' => 'admin::app.acl.configuration',
|
||||
'route' => 'admin.configuration.index',
|
||||
'sort' => 9,
|
||||
],
|
||||
];
|
||||
33
packages/Webkul/Admin/src/Config/attribute_entity_types.php
Normal file
33
packages/Webkul/Admin/src/Config/attribute_entity_types.php
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'leads' => [
|
||||
'name' => 'admin::app.leads.index.title',
|
||||
'repository' => 'Webkul\Lead\Repositories\LeadRepository',
|
||||
],
|
||||
|
||||
'persons' => [
|
||||
'name' => 'admin::app.contacts.persons.index.title',
|
||||
'repository' => 'Webkul\Contact\Repositories\PersonRepository',
|
||||
],
|
||||
|
||||
'organizations' => [
|
||||
'name' => 'admin::app.contacts.organizations.index.title',
|
||||
'repository' => 'Webkul\Contact\Repositories\OrganizationRepository',
|
||||
],
|
||||
|
||||
'products' => [
|
||||
'name' => 'admin::app.products.index.title',
|
||||
'repository' => 'Webkul\Product\Repositories\ProductRepository',
|
||||
],
|
||||
|
||||
'quotes' => [
|
||||
'name' => 'admin::app.quotes.index.title',
|
||||
'repository' => 'Webkul\Quote\Repositories\QuoteRepository',
|
||||
],
|
||||
|
||||
'warehouses' => [
|
||||
'name' => 'admin::app.settings.warehouses.index.title',
|
||||
'repository' => 'Webkul\Warehouse\Repositories\WarehouseRepository',
|
||||
],
|
||||
];
|
||||
54
packages/Webkul/Admin/src/Config/attribute_lookups.php
Normal file
54
packages/Webkul/Admin/src/Config/attribute_lookups.php
Normal file
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'leads' => [
|
||||
'name' => 'Leads',
|
||||
'repository' => 'Webkul\Lead\Repositories\LeadRepository',
|
||||
'label_column' => 'title',
|
||||
],
|
||||
|
||||
'lead_sources' => [
|
||||
'name' => 'Lead Sources',
|
||||
'repository' => 'Webkul\Lead\Repositories\SourceRepository',
|
||||
],
|
||||
|
||||
'lead_types' => [
|
||||
'name' => 'Lead Types',
|
||||
'repository' => 'Webkul\Lead\Repositories\TypeRepository',
|
||||
],
|
||||
|
||||
'lead_pipelines' => [
|
||||
'name' => 'Lead Pipelines',
|
||||
'repository' => 'Webkul\Lead\Repositories\PipelineRepository',
|
||||
],
|
||||
|
||||
'lead_pipeline_stages' => [
|
||||
'name' => 'Lead Pipeline Stages',
|
||||
'repository' => 'Webkul\Lead\Repositories\StageRepository',
|
||||
],
|
||||
|
||||
'users' => [
|
||||
'name' => 'Sales Owners',
|
||||
'repository' => 'Webkul\User\Repositories\UserRepository',
|
||||
],
|
||||
|
||||
'organizations' => [
|
||||
'name' => 'Organizations',
|
||||
'repository' => 'Webkul\Contact\Repositories\OrganizationRepository',
|
||||
],
|
||||
|
||||
'persons' => [
|
||||
'name' => 'Persons',
|
||||
'repository' => 'Webkul\Contact\Repositories\PersonRepository',
|
||||
],
|
||||
|
||||
'warehouses' => [
|
||||
'name' => 'Warehouses',
|
||||
'repository' => 'Webkul\Warehouse\Repositories\WarehouseRepository',
|
||||
],
|
||||
|
||||
'locations' => [
|
||||
'name' => 'Locations',
|
||||
'repository' => 'Webkul\Warehouse\Repositories\LocationRepository',
|
||||
],
|
||||
];
|
||||
314
packages/Webkul/Admin/src/Config/core_config.php
Normal file
314
packages/Webkul/Admin/src/Config/core_config.php
Normal file
@@ -0,0 +1,314 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
/**
|
||||
* General.
|
||||
*/
|
||||
[
|
||||
'key' => 'general',
|
||||
'name' => 'admin::app.configuration.index.general.title',
|
||||
'info' => 'admin::app.configuration.index.general.info',
|
||||
'sort' => 1,
|
||||
], [
|
||||
'key' => 'general.general',
|
||||
'name' => 'admin::app.configuration.index.general.general.title',
|
||||
'info' => 'admin::app.configuration.index.general.general.info',
|
||||
'icon' => 'icon-setting',
|
||||
'sort' => 1,
|
||||
], [
|
||||
'key' => 'general.general.locale_settings',
|
||||
'name' => 'admin::app.configuration.index.general.general.locale-settings.title',
|
||||
'info' => 'admin::app.configuration.index.general.general.locale-settings.title-info',
|
||||
'sort' => 1,
|
||||
'fields' => [
|
||||
[
|
||||
'name' => 'locale',
|
||||
'title' => 'admin::app.configuration.index.general.general.locale-settings.title',
|
||||
'type' => 'select',
|
||||
'default' => 'en',
|
||||
'options' => 'Webkul\Core\Core@locales',
|
||||
],
|
||||
],
|
||||
], [
|
||||
'key' => 'general.general.admin_logo',
|
||||
'name' => 'admin::app.configuration.index.general.general.admin-logo.title',
|
||||
'info' => 'admin::app.configuration.index.general.general.admin-logo.title-info',
|
||||
'sort' => 2,
|
||||
'fields' => [
|
||||
[
|
||||
'name' => 'logo_image',
|
||||
'title' => 'admin::app.configuration.index.general.general.admin-logo.logo-image',
|
||||
'type' => 'image',
|
||||
'validation' => 'mimes:bmp,jpeg,jpg,png,webp,svg',
|
||||
],
|
||||
],
|
||||
], [
|
||||
'key' => 'general.settings',
|
||||
'name' => 'admin::app.configuration.index.general.settings.title',
|
||||
'info' => 'admin::app.configuration.index.general.settings.info',
|
||||
'icon' => 'icon-configuration',
|
||||
'sort' => 2,
|
||||
], [
|
||||
'key' => 'general.settings.footer',
|
||||
'name' => 'admin::app.configuration.index.general.settings.footer.title',
|
||||
'info' => 'admin::app.configuration.index.general.settings.footer.info',
|
||||
'sort' => 1,
|
||||
'fields' => [
|
||||
[
|
||||
'name' => 'label',
|
||||
'title' => 'admin::app.configuration.index.general.settings.footer.powered-by',
|
||||
'type' => 'editor',
|
||||
'default' => 'Powered by <span style="color: rgb(14, 144, 217);"><a href="http://www.krayincrm.com" target="_blank">Krayin</a></span>, an open-source project by <span style="color: rgb(14, 144, 217);"><a href="https://webkul.com" target="_blank">Webkul</a></span>.',
|
||||
'tinymce' => true,
|
||||
],
|
||||
],
|
||||
], [
|
||||
'key' => 'general.settings.menu',
|
||||
'name' => 'admin::app.configuration.index.general.settings.menu.title',
|
||||
'info' => 'admin::app.configuration.index.general.settings.menu.info',
|
||||
'sort' => 2,
|
||||
'fields' => [
|
||||
[
|
||||
'name' => 'dashboard',
|
||||
'title' => 'admin::app.configuration.index.general.settings.menu.dashboard',
|
||||
'type' => 'text',
|
||||
'default' => 'Dashboard',
|
||||
'validation' => 'max:20',
|
||||
], [
|
||||
'name' => 'leads',
|
||||
'title' => 'admin::app.configuration.index.general.settings.menu.leads',
|
||||
'type' => 'text',
|
||||
'default' => 'Leads',
|
||||
'validation' => 'max:20',
|
||||
], [
|
||||
'name' => 'quotes',
|
||||
'title' => 'admin::app.configuration.index.general.settings.menu.quotes',
|
||||
'type' => 'text',
|
||||
'default' => 'Quotes',
|
||||
'validation' => 'max:20',
|
||||
], [
|
||||
'name' => 'mail.mail',
|
||||
'title' => 'admin::app.configuration.index.general.settings.menu.mail',
|
||||
'type' => 'text',
|
||||
'default' => 'Mail',
|
||||
'validation' => 'max:20',
|
||||
], [
|
||||
'name' => 'mail.inbox',
|
||||
'title' => 'admin::app.configuration.index.general.settings.menu.inbox',
|
||||
'type' => 'text',
|
||||
'default' => 'Inbox',
|
||||
'validation' => 'max:20',
|
||||
], [
|
||||
'name' => 'mail.draft',
|
||||
'title' => 'admin::app.configuration.index.general.settings.menu.draft',
|
||||
'type' => 'text',
|
||||
'default' => 'Draft',
|
||||
'validation' => 'max:20',
|
||||
], [
|
||||
'name' => 'mail.outbox',
|
||||
'title' => 'admin::app.configuration.index.general.settings.menu.outbox',
|
||||
'type' => 'text',
|
||||
'default' => 'Outbox',
|
||||
'validation' => 'max:20',
|
||||
], [
|
||||
'name' => 'mail.sent',
|
||||
'title' => 'admin::app.configuration.index.general.settings.menu.sent',
|
||||
'type' => 'text',
|
||||
'default' => 'Sent',
|
||||
'validation' => 'max:20',
|
||||
], [
|
||||
'name' => 'mail.trash',
|
||||
'title' => 'admin::app.configuration.index.general.settings.menu.trash',
|
||||
'type' => 'text',
|
||||
'default' => 'Trash',
|
||||
'validation' => 'max:20',
|
||||
], [
|
||||
'name' => 'activities',
|
||||
'title' => 'admin::app.configuration.index.general.settings.menu.activities',
|
||||
'type' => 'text',
|
||||
'default' => 'Activities',
|
||||
'validation' => 'max:20',
|
||||
], [
|
||||
'name' => 'contacts.contacts',
|
||||
'title' => 'admin::app.configuration.index.general.settings.menu.contacts',
|
||||
'type' => 'text',
|
||||
'default' => 'Contacts',
|
||||
'validation' => 'max:20',
|
||||
], [
|
||||
'name' => 'contacts.persons',
|
||||
'title' => 'admin::app.configuration.index.general.settings.menu.persons',
|
||||
'type' => 'text',
|
||||
'default' => 'Persons',
|
||||
'validation' => 'max:20',
|
||||
], [
|
||||
'name' => 'contacts.organizations',
|
||||
'title' => 'admin::app.configuration.index.general.settings.menu.organizations',
|
||||
'type' => 'text',
|
||||
'default' => 'Organizations',
|
||||
'validation' => 'max:20',
|
||||
], [
|
||||
'name' => 'products',
|
||||
'title' => 'admin::app.configuration.index.general.settings.menu.products',
|
||||
'type' => 'text',
|
||||
'default' => 'Products',
|
||||
'validation' => 'max:20',
|
||||
], [
|
||||
'name' => 'settings',
|
||||
'title' => 'admin::app.configuration.index.general.settings.menu.settings',
|
||||
'type' => 'text',
|
||||
'default' => 'Settings',
|
||||
'validation' => 'max:20',
|
||||
], [
|
||||
'name' => 'configuration',
|
||||
'title' => 'admin::app.configuration.index.general.settings.menu.configuration',
|
||||
'type' => 'text',
|
||||
'default' => 'Configuration',
|
||||
'validation' => 'max:20',
|
||||
],
|
||||
],
|
||||
], [
|
||||
'key' => 'general.settings.menu_color',
|
||||
'name' => 'admin::app.configuration.index.general.settings.menu-color.title',
|
||||
'info' => 'admin::app.configuration.index.general.settings.menu-color.info',
|
||||
'sort' => 3,
|
||||
'fields' => [
|
||||
[
|
||||
'name' => 'brand_color',
|
||||
'title' => 'admin::app.configuration.index.general.settings.menu-color.brand-color',
|
||||
'type' => 'color',
|
||||
'default' => '#0E90D9',
|
||||
],
|
||||
],
|
||||
], [
|
||||
'key' => 'general.magic_ai',
|
||||
'name' => 'admin::app.configuration.index.magic-ai.title',
|
||||
'info' => 'admin::app.configuration.index.magic-ai.info',
|
||||
'icon' => 'icon-setting',
|
||||
'sort' => 3,
|
||||
], [
|
||||
'key' => 'general.magic_ai.settings',
|
||||
'name' => 'admin::app.configuration.index.magic-ai.settings.title',
|
||||
'info' => 'admin::app.configuration.index.magic-ai.settings.info',
|
||||
'sort' => 1,
|
||||
'fields' => [
|
||||
[
|
||||
'name' => 'enable',
|
||||
'title' => 'admin::app.configuration.index.magic-ai.settings.enable',
|
||||
'type' => 'boolean',
|
||||
'channel_based' => true,
|
||||
], [
|
||||
'name' => 'api_key',
|
||||
'title' => 'admin::app.configuration.index.magic-ai.settings.api-key',
|
||||
'type' => 'password',
|
||||
'depends' => 'enable:1',
|
||||
'validation' => 'required_if:enable,1',
|
||||
'info' => 'admin::app.configuration.index.magic-ai.settings.api-key-info',
|
||||
], [
|
||||
'name' => 'model',
|
||||
'title' => 'admin::app.configuration.index.magic-ai.settings.models.title',
|
||||
'type' => 'select',
|
||||
'channel_based' => true,
|
||||
'depends' => 'enable:1',
|
||||
'options' => [
|
||||
[
|
||||
'title' => 'admin::app.configuration.index.magic-ai.settings.models.gpt-4o',
|
||||
'value' => 'openai/chatgpt-4o-latest',
|
||||
], [
|
||||
'title' => 'admin::app.configuration.index.magic-ai.settings.models.gpt-4o-mini',
|
||||
'value' => 'openai/gpt-4o-mini',
|
||||
], [
|
||||
'title' => 'admin::app.configuration.index.magic-ai.settings.models.gemini-2-0-flash-001',
|
||||
'value' => 'google/gemini-2.0-flash-001',
|
||||
], [
|
||||
'title' => 'admin::app.configuration.index.magic-ai.settings.models.deepseek-r1',
|
||||
'value' => 'deepseek/deepseek-r1-distill-llama-8b',
|
||||
], [
|
||||
'title' => 'admin::app.configuration.index.magic-ai.settings.models.llama-3-2-3b-instruct',
|
||||
'value' => 'meta-llama/llama-3.2-3b-instruct',
|
||||
], [
|
||||
'title' => 'admin::app.configuration.index.magic-ai.settings.models.grok-2-1212',
|
||||
'value' => 'x-ai/grok-2-1212',
|
||||
],
|
||||
],
|
||||
], [
|
||||
'name' => 'other_model',
|
||||
'title' => 'admin::app.configuration.index.magic-ai.settings.other',
|
||||
'type' => 'text',
|
||||
'info' => 'admin::app.configuration.index.magic-ai.settings.other-model',
|
||||
'default' => null,
|
||||
'depends' => 'enable:1',
|
||||
],
|
||||
],
|
||||
], [
|
||||
'key' => 'general.magic_ai.doc_generation',
|
||||
'name' => 'admin::app.configuration.index.magic-ai.settings.doc-generation',
|
||||
'info' => 'admin::app.configuration.index.magic-ai.settings.doc-generation-info',
|
||||
'sort' => 2,
|
||||
'fields' => [
|
||||
[
|
||||
'name' => 'enabled',
|
||||
'title' => 'admin::app.configuration.index.magic-ai.settings.enable',
|
||||
'type' => 'boolean',
|
||||
],
|
||||
],
|
||||
],
|
||||
|
||||
/**
|
||||
* Email.
|
||||
*/
|
||||
[
|
||||
'key' => 'email',
|
||||
'name' => 'admin::app.configuration.index.email.title',
|
||||
'info' => 'admin::app.configuration.index.email.info',
|
||||
'sort' => 2,
|
||||
], [
|
||||
'key' => 'email.imap',
|
||||
'name' => 'admin::app.configuration.index.email.imap.title',
|
||||
'info' => 'admin::app.configuration.index.email.imap.info',
|
||||
'icon' => 'icon-setting',
|
||||
'sort' => 1,
|
||||
], [
|
||||
'key' => 'email.imap.account',
|
||||
'name' => 'admin::app.configuration.index.email.imap.account.title',
|
||||
'info' => 'admin::app.configuration.index.email.imap.account.title-info',
|
||||
'sort' => 1,
|
||||
'fields' => [
|
||||
[
|
||||
'name' => 'host',
|
||||
'title' => 'admin::app.configuration.index.email.imap.account.host',
|
||||
'type' => 'text',
|
||||
'default' => config('imap.accounts.default.host'),
|
||||
],
|
||||
[
|
||||
'name' => 'port',
|
||||
'title' => 'admin::app.configuration.index.email.imap.account.port',
|
||||
'type' => 'text',
|
||||
'default' => config('imap.accounts.default.port'),
|
||||
],
|
||||
[
|
||||
'name' => 'encryption',
|
||||
'title' => 'admin::app.configuration.index.email.imap.account.encryption',
|
||||
'type' => 'text',
|
||||
'default' => config('imap.accounts.default.encryption'),
|
||||
],
|
||||
[
|
||||
'name' => 'validate_cert',
|
||||
'title' => 'admin::app.configuration.index.email.imap.account.validate-cert',
|
||||
'type' => 'boolean',
|
||||
'default' => config('imap.accounts.default.validate_cert'),
|
||||
],
|
||||
[
|
||||
'name' => 'username',
|
||||
'title' => 'admin::app.configuration.index.email.imap.account.username',
|
||||
'type' => 'text',
|
||||
'default' => config('imap.accounts.default.username'),
|
||||
],
|
||||
[
|
||||
'name' => 'password',
|
||||
'title' => 'admin::app.configuration.index.email.imap.account.password',
|
||||
'type' => 'password',
|
||||
'default' => config('imap.accounts.default.password'),
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
299
packages/Webkul/Admin/src/Config/menu.php
Normal file
299
packages/Webkul/Admin/src/Config/menu.php
Normal file
@@ -0,0 +1,299 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
/**
|
||||
* Dashboard.
|
||||
*/
|
||||
[
|
||||
'key' => 'dashboard',
|
||||
'name' => 'admin::app.layouts.dashboard',
|
||||
'route' => 'admin.dashboard.index',
|
||||
'sort' => 1,
|
||||
'icon-class' => 'icon-dashboard',
|
||||
],
|
||||
|
||||
/**
|
||||
* Leads.
|
||||
*/
|
||||
[
|
||||
'key' => 'leads',
|
||||
'name' => 'admin::app.layouts.leads',
|
||||
'route' => 'admin.leads.index',
|
||||
'sort' => 2,
|
||||
'icon-class' => 'icon-leads',
|
||||
],
|
||||
|
||||
/**
|
||||
* Quotes.
|
||||
*/
|
||||
[
|
||||
'key' => 'quotes',
|
||||
'name' => 'admin::app.layouts.quotes',
|
||||
'route' => 'admin.quotes.index',
|
||||
'sort' => 3,
|
||||
'icon-class' => 'icon-quote',
|
||||
],
|
||||
|
||||
/**
|
||||
* Emails.
|
||||
*/
|
||||
[
|
||||
'key' => 'mail',
|
||||
'name' => 'admin::app.layouts.mail.title',
|
||||
'route' => 'admin.mail.index',
|
||||
'params' => ['route' => 'inbox'],
|
||||
'sort' => 4,
|
||||
'icon-class' => 'icon-mail',
|
||||
], [
|
||||
'key' => 'mail.inbox',
|
||||
'name' => 'admin::app.layouts.mail.inbox',
|
||||
'route' => 'admin.mail.index',
|
||||
'params' => ['route' => 'inbox'],
|
||||
'sort' => 2,
|
||||
'icon-class' => '',
|
||||
], [
|
||||
'key' => 'mail.draft',
|
||||
'name' => 'admin::app.layouts.mail.draft',
|
||||
'route' => 'admin.mail.index',
|
||||
'params' => ['route' => 'draft'],
|
||||
'sort' => 3,
|
||||
'icon-class' => '',
|
||||
], [
|
||||
'key' => 'mail.outbox',
|
||||
'name' => 'admin::app.layouts.mail.outbox',
|
||||
'route' => 'admin.mail.index',
|
||||
'params' => ['route' => 'outbox'],
|
||||
'sort' => 4,
|
||||
'icon-class' => '',
|
||||
], [
|
||||
'key' => 'mail.sent',
|
||||
'name' => 'admin::app.layouts.mail.sent',
|
||||
'route' => 'admin.mail.index',
|
||||
'params' => ['route' => 'sent'],
|
||||
'sort' => 4,
|
||||
'icon-class' => '',
|
||||
], [
|
||||
'key' => 'mail.trash',
|
||||
'name' => 'admin::app.layouts.mail.trash',
|
||||
'route' => 'admin.mail.index',
|
||||
'params' => ['route' => 'trash'],
|
||||
'sort' => 5,
|
||||
'icon-class' => '',
|
||||
],
|
||||
// , [
|
||||
// 'key' => 'mail.setting',
|
||||
// 'name' => 'admin::app.layouts.mail.setting',
|
||||
// 'route' => 'admin.mail.index',
|
||||
// 'params' => ['route' => 'setting'],
|
||||
// 'sort' => 5,
|
||||
// ]
|
||||
|
||||
/**
|
||||
* Activities.
|
||||
*/
|
||||
[
|
||||
'key' => 'activities',
|
||||
'name' => 'admin::app.layouts.activities',
|
||||
'route' => 'admin.activities.index',
|
||||
'sort' => 5,
|
||||
'icon-class' => 'icon-activity',
|
||||
],
|
||||
|
||||
/**
|
||||
* Contacts.
|
||||
*/
|
||||
[
|
||||
'key' => 'contacts',
|
||||
'name' => 'admin::app.layouts.contacts',
|
||||
'route' => 'admin.contacts.persons.index',
|
||||
'sort' => 6,
|
||||
'icon-class' => 'icon-contact',
|
||||
], [
|
||||
'key' => 'contacts.persons',
|
||||
'name' => 'admin::app.layouts.persons',
|
||||
'route' => 'admin.contacts.persons.index',
|
||||
'sort' => 1,
|
||||
'icon-class' => '',
|
||||
], [
|
||||
'key' => 'contacts.organizations',
|
||||
'name' => 'admin::app.layouts.organizations',
|
||||
'route' => 'admin.contacts.organizations.index',
|
||||
'sort' => 2,
|
||||
'icon-class' => '',
|
||||
],
|
||||
|
||||
/**
|
||||
* Products.
|
||||
*/
|
||||
[
|
||||
'key' => 'products',
|
||||
'name' => 'admin::app.layouts.products',
|
||||
'route' => 'admin.products.index',
|
||||
'sort' => 7,
|
||||
'icon-class' => 'icon-product',
|
||||
],
|
||||
|
||||
/**
|
||||
* Settings.
|
||||
*/
|
||||
[
|
||||
'key' => 'settings',
|
||||
'name' => 'admin::app.layouts.settings',
|
||||
'route' => 'admin.settings.index',
|
||||
'sort' => 8,
|
||||
'icon-class' => 'icon-setting',
|
||||
], [
|
||||
'key' => 'settings.user',
|
||||
'name' => 'admin::app.layouts.user',
|
||||
'route' => 'admin.settings.groups.index',
|
||||
'info' => 'admin::app.layouts.user-info',
|
||||
'sort' => 1,
|
||||
'icon-class' => 'icon-settings-group',
|
||||
], [
|
||||
'key' => 'settings.user.groups',
|
||||
'name' => 'admin::app.layouts.groups',
|
||||
'info' => 'admin::app.layouts.groups-info',
|
||||
'route' => 'admin.settings.groups.index',
|
||||
'sort' => 1,
|
||||
'icon-class' => 'icon-settings-group',
|
||||
], [
|
||||
'key' => 'settings.user.roles',
|
||||
'name' => 'admin::app.layouts.roles',
|
||||
'info' => 'admin::app.layouts.roles-info',
|
||||
'route' => 'admin.settings.roles.index',
|
||||
'sort' => 2,
|
||||
'icon-class' => 'icon-role',
|
||||
], [
|
||||
'key' => 'settings.user.users',
|
||||
'name' => 'admin::app.layouts.users',
|
||||
'info' => 'admin::app.layouts.users-info',
|
||||
'route' => 'admin.settings.users.index',
|
||||
'sort' => 3,
|
||||
'icon-class' => 'icon-user',
|
||||
], [
|
||||
'key' => 'settings.lead',
|
||||
'name' => 'admin::app.layouts.lead',
|
||||
'info' => 'admin::app.layouts.lead-info',
|
||||
'route' => 'admin.settings.pipelines.index',
|
||||
'sort' => 2,
|
||||
'icon-class' => '',
|
||||
], [
|
||||
'key' => 'settings.lead.pipelines',
|
||||
'name' => 'admin::app.layouts.pipelines',
|
||||
'info' => 'admin::app.layouts.pipelines-info',
|
||||
'route' => 'admin.settings.pipelines.index',
|
||||
'sort' => 1,
|
||||
'icon-class' => 'icon-settings-pipeline',
|
||||
], [
|
||||
'key' => 'settings.lead.sources',
|
||||
'name' => 'admin::app.layouts.sources',
|
||||
'info' => 'admin::app.layouts.sources-info',
|
||||
'route' => 'admin.settings.sources.index',
|
||||
'sort' => 2,
|
||||
'icon-class' => 'icon-settings-sources',
|
||||
], [
|
||||
'key' => 'settings.lead.types',
|
||||
'name' => 'admin::app.layouts.types',
|
||||
'info' => 'admin::app.layouts.types-info',
|
||||
'route' => 'admin.settings.types.index',
|
||||
'sort' => 3,
|
||||
'icon-class' => 'icon-settings-type',
|
||||
], [
|
||||
'key' => 'settings.warehouse',
|
||||
'name' => 'admin::app.layouts.warehouse',
|
||||
'info' => 'admin::app.layouts.warehouses-info',
|
||||
'route' => 'admin.settings.pipelines.index',
|
||||
'icon-class' => '',
|
||||
'sort' => 2,
|
||||
], [
|
||||
'key' => 'settings.warehouse.warehouses',
|
||||
'name' => 'admin::app.layouts.warehouses',
|
||||
'info' => 'admin::app.layouts.warehouses-info',
|
||||
'route' => 'admin.settings.warehouses.index',
|
||||
'sort' => 1,
|
||||
'icon-class' => 'icon-settings-warehouse',
|
||||
], [
|
||||
'key' => 'settings.automation',
|
||||
'name' => 'admin::app.layouts.automation',
|
||||
'info' => 'admin::app.layouts.automation-info',
|
||||
'route' => 'admin.settings.attributes.index',
|
||||
'sort' => 3,
|
||||
'icon-class' => '',
|
||||
], [
|
||||
'key' => 'settings.automation.attributes',
|
||||
'name' => 'admin::app.layouts.attributes',
|
||||
'info' => 'admin::app.layouts.attributes-info',
|
||||
'route' => 'admin.settings.attributes.index',
|
||||
'sort' => 1,
|
||||
'icon-class' => 'icon-attribute',
|
||||
], [
|
||||
'key' => 'settings.automation.email_templates',
|
||||
'name' => 'admin::app.layouts.email-templates',
|
||||
'info' => 'admin::app.layouts.email-templates-info',
|
||||
'route' => 'admin.settings.email_templates.index',
|
||||
'sort' => 2,
|
||||
'icon-class' => 'icon-settings-mail',
|
||||
], [
|
||||
'key' => 'settings.automation.events',
|
||||
'name' => 'admin::app.layouts.events',
|
||||
'info' => 'admin::app.layouts.events-info',
|
||||
'route' => 'admin.settings.marketing.events.index',
|
||||
'sort' => 2,
|
||||
'icon-class' => 'icon-calendar',
|
||||
], [
|
||||
'key' => 'settings.automation.campaigns',
|
||||
'name' => 'admin::app.layouts.campaigns',
|
||||
'info' => 'admin::app.layouts.campaigns-info',
|
||||
'route' => 'admin.settings.marketing.campaigns.index',
|
||||
'sort' => 2,
|
||||
'icon-class' => 'icon-note',
|
||||
], [
|
||||
'key' => 'settings.automation.webhooks',
|
||||
'name' => 'admin::app.layouts.webhooks',
|
||||
'info' => 'admin::app.layouts.webhooks-info',
|
||||
'route' => 'admin.settings.webhooks.index',
|
||||
'sort' => 2,
|
||||
'icon-class' => 'icon-settings-webhooks',
|
||||
], [
|
||||
'key' => 'settings.automation.workflows',
|
||||
'name' => 'admin::app.layouts.workflows',
|
||||
'info' => 'admin::app.layouts.workflows-info',
|
||||
'route' => 'admin.settings.workflows.index',
|
||||
'sort' => 3,
|
||||
'icon-class' => 'icon-settings-flow',
|
||||
],
|
||||
[
|
||||
'key' => 'settings.automation.data_transfer',
|
||||
'name' => 'admin::app.layouts.data_transfer',
|
||||
'info' => 'admin::app.layouts.data_transfer_info',
|
||||
'route' => 'admin.settings.data_transfer.imports.index',
|
||||
'sort' => 4,
|
||||
'icon-class' => 'icon-download',
|
||||
], [
|
||||
'key' => 'settings.other_settings',
|
||||
'name' => 'admin::app.layouts.other-settings',
|
||||
'info' => 'admin::app.layouts.other-settings-info',
|
||||
'route' => 'admin.settings.tags.index',
|
||||
'sort' => 4,
|
||||
'icon-class' => 'icon-settings',
|
||||
], [
|
||||
'key' => 'settings.other_settings.tags',
|
||||
'name' => 'admin::app.layouts.tags',
|
||||
'info' => 'admin::app.layouts.tags-info',
|
||||
'route' => 'admin.settings.tags.index',
|
||||
'sort' => 1,
|
||||
'icon-class' => 'icon-settings-tag',
|
||||
],
|
||||
|
||||
/**
|
||||
* Configuration.
|
||||
*/
|
||||
[
|
||||
'key' => 'configuration',
|
||||
'name' => 'admin::app.layouts.configuration',
|
||||
'route' => 'admin.configuration.index',
|
||||
'sort' => 9,
|
||||
'icon-class' => 'icon-configuration',
|
||||
],
|
||||
|
||||
];
|
||||
@@ -0,0 +1,235 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Admin\DataGrids\Activity;
|
||||
|
||||
use Illuminate\Database\Query\Builder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Webkul\Admin\Traits\ProvideDropdownOptions;
|
||||
use Webkul\DataGrid\DataGrid;
|
||||
use Webkul\Lead\Repositories\LeadRepository;
|
||||
use Webkul\User\Repositories\UserRepository;
|
||||
|
||||
class ActivityDataGrid extends DataGrid
|
||||
{
|
||||
use ProvideDropdownOptions;
|
||||
|
||||
/**
|
||||
* Prepare query builder.
|
||||
*/
|
||||
public function prepareQueryBuilder(): Builder
|
||||
{
|
||||
$queryBuilder = DB::table('activities')
|
||||
->distinct()
|
||||
->select(
|
||||
'activities.*',
|
||||
'leads.id as lead_id',
|
||||
'leads.title as lead_title',
|
||||
'leads.lead_pipeline_id',
|
||||
'users.id as created_by_id',
|
||||
'users.name as created_by',
|
||||
)
|
||||
->leftJoin('activity_participants', 'activities.id', '=', 'activity_participants.activity_id')
|
||||
->leftJoin('lead_activities', 'activities.id', '=', 'lead_activities.activity_id')
|
||||
->leftJoin('leads', 'lead_activities.lead_id', '=', 'leads.id')
|
||||
->leftJoin('users', 'activities.user_id', '=', 'users.id')
|
||||
->whereIn('type', ['call', 'meeting', 'lunch'])
|
||||
->where(function ($query) {
|
||||
if ($userIds = bouncer()->getAuthorizedUserIds()) {
|
||||
$query->whereIn('activities.user_id', $userIds)
|
||||
->orWhereIn('activity_participants.user_id', $userIds);
|
||||
}
|
||||
})->groupBy('activities.id', 'leads.id', 'users.id');
|
||||
|
||||
$this->addFilter('id', 'activities.id');
|
||||
$this->addFilter('title', 'activities.title');
|
||||
$this->addFilter('schedule_from', 'activities.schedule_from');
|
||||
$this->addFilter('created_by', 'users.name');
|
||||
$this->addFilter('created_by_id', 'users.name');
|
||||
$this->addFilter('created_at', 'activities.created_at');
|
||||
$this->addFilter('lead_title', 'leads.title');
|
||||
|
||||
return $queryBuilder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare columns.
|
||||
*/
|
||||
public function prepareColumns(): void
|
||||
{
|
||||
$this->addColumn([
|
||||
'index' => 'id',
|
||||
'label' => trans('admin::app.activities.index.datagrid.id'),
|
||||
'type' => 'integer',
|
||||
'searchable' => true,
|
||||
'filterable' => true,
|
||||
'sortable' => true,
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'is_done',
|
||||
'label' => trans('admin::app.activities.index.datagrid.is_done'),
|
||||
'type' => 'string',
|
||||
'dropdown_options' => $this->getBooleanDropdownOptions('yes_no'),
|
||||
'searchable' => false,
|
||||
'closure' => fn ($row) => view('admin::activities.datagrid.is-done', compact('row'))->render(),
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'title',
|
||||
'label' => trans('admin::app.activities.index.datagrid.title'),
|
||||
'type' => 'string',
|
||||
'searchable' => true,
|
||||
'filterable' => true,
|
||||
'sortable' => true,
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'created_by_id',
|
||||
'label' => trans('admin::app.activities.index.datagrid.created_by'),
|
||||
'type' => 'string',
|
||||
'searchable' => false,
|
||||
'sortable' => true,
|
||||
'filterable' => true,
|
||||
'filterable_type' => 'searchable_dropdown',
|
||||
'filterable_options' => [
|
||||
'repository' => UserRepository::class,
|
||||
'column' => [
|
||||
'label' => 'name',
|
||||
'value' => 'name',
|
||||
],
|
||||
],
|
||||
'closure' => function ($row) {
|
||||
$route = urldecode(route('admin.settings.users.index', ['id[eq]' => $row->created_by_id]));
|
||||
|
||||
return "<a class='text-brandColor hover:underline' href='".$route."'>".$row->created_by.'</a>';
|
||||
},
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'comment',
|
||||
'label' => trans('admin::app.activities.index.datagrid.comment'),
|
||||
'type' => 'string',
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'lead_title',
|
||||
'label' => trans('admin::app.activities.index.datagrid.lead'),
|
||||
'type' => 'string',
|
||||
'searchable' => true,
|
||||
'sortable' => true,
|
||||
'filterable' => true,
|
||||
'filterable_type' => 'searchable_dropdown',
|
||||
'filterable_options' => [
|
||||
'repository' => LeadRepository::class,
|
||||
'column' => [
|
||||
'label' => 'title',
|
||||
'value' => 'title',
|
||||
],
|
||||
],
|
||||
'closure' => function ($row) {
|
||||
if ($row->lead_title == null) {
|
||||
return "<span class='text-gray-800 dark:text-gray-300'>N/A</span>";
|
||||
}
|
||||
|
||||
$route = urldecode(route('admin.leads.view', $row->lead_id));
|
||||
|
||||
return "<a class='text-brandColor hover:underline' target='_blank' href='".$route."'>".$row->lead_title.'</a>';
|
||||
},
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'type',
|
||||
'label' => trans('admin::app.activities.index.datagrid.type'),
|
||||
'type' => 'string',
|
||||
'searchable' => false,
|
||||
'filterable' => false,
|
||||
'sortable' => true,
|
||||
'closure' => fn ($row) => trans('admin::app.activities.index.datagrid.'.$row->type),
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'schedule_from',
|
||||
'label' => trans('admin::app.activities.index.datagrid.schedule_from'),
|
||||
'type' => 'date',
|
||||
'sortable' => true,
|
||||
'searchable' => true,
|
||||
'filterable' => true,
|
||||
'closure' => fn ($row) => core()->formatDate($row->schedule_from),
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'schedule_to',
|
||||
'label' => trans('admin::app.activities.index.datagrid.schedule_to'),
|
||||
'type' => 'date',
|
||||
'sortable' => true,
|
||||
'searchable' => true,
|
||||
'filterable' => true,
|
||||
'closure' => fn ($row) => core()->formatDate($row->schedule_to),
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'created_at',
|
||||
'label' => trans('admin::app.activities.index.datagrid.created_at'),
|
||||
'type' => 'date',
|
||||
'sortable' => true,
|
||||
'searchable' => true,
|
||||
'filterable' => true,
|
||||
'closure' => fn ($row) => core()->formatDate($row->created_at),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare actions.
|
||||
*/
|
||||
public function prepareActions(): void
|
||||
{
|
||||
if (bouncer()->hasPermission('activities.edit')) {
|
||||
$this->addAction([
|
||||
'index' => 'edit',
|
||||
'icon' => 'icon-edit',
|
||||
'title' => trans('admin::app.activities.index.datagrid.edit'),
|
||||
'method' => 'GET',
|
||||
'url' => fn ($row) => route('admin.activities.edit', $row->id),
|
||||
]);
|
||||
}
|
||||
|
||||
if (bouncer()->hasPermission('activities.delete')) {
|
||||
$this->addAction([
|
||||
'index' => 'delete',
|
||||
'icon' => 'icon-delete',
|
||||
'title' => trans('admin::app.activities.index.datagrid.update'),
|
||||
'method' => 'DELETE',
|
||||
'url' => fn ($row) => route('admin.activities.delete', $row->id),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare mass actions.
|
||||
*/
|
||||
public function prepareMassActions(): void
|
||||
{
|
||||
|
||||
$this->addMassAction([
|
||||
'icon' => 'icon-delete',
|
||||
'title' => trans('admin::app.activities.index.datagrid.mass-delete'),
|
||||
'method' => 'POST',
|
||||
'url' => route('admin.activities.mass_delete'),
|
||||
]);
|
||||
|
||||
$this->addMassAction([
|
||||
'title' => trans('admin::app.activities.index.datagrid.mass-update'),
|
||||
'url' => route('admin.activities.mass_update'),
|
||||
'method' => 'POST',
|
||||
'options' => [
|
||||
[
|
||||
'label' => trans('admin::app.activities.index.datagrid.done'),
|
||||
'value' => 1,
|
||||
], [
|
||||
'label' => trans('admin::app.activities.index.datagrid.not-done'),
|
||||
'value' => 0,
|
||||
],
|
||||
],
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Admin\DataGrids\Contact;
|
||||
|
||||
use Illuminate\Database\Query\Builder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Webkul\Contact\Repositories\PersonRepository;
|
||||
use Webkul\DataGrid\DataGrid;
|
||||
|
||||
class OrganizationDataGrid extends DataGrid
|
||||
{
|
||||
/**
|
||||
* Create datagrid instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(protected PersonRepository $personRepository) {}
|
||||
|
||||
/**
|
||||
* Prepare query builder.
|
||||
*/
|
||||
public function prepareQueryBuilder(): Builder
|
||||
{
|
||||
return DB::table('organizations')
|
||||
->addSelect(
|
||||
'organizations.id',
|
||||
'organizations.name',
|
||||
'organizations.address',
|
||||
'organizations.created_at'
|
||||
);
|
||||
|
||||
if ($userIds = bouncer()->getAuthorizedUserIds()) {
|
||||
$queryBuilder->whereIn('organizations.user_id', $userIds);
|
||||
}
|
||||
|
||||
$this->addFilter('id', 'organizations.id');
|
||||
|
||||
$this->addFilter('organization', 'organizations.name');
|
||||
}
|
||||
|
||||
/**
|
||||
* Add columns.
|
||||
*/
|
||||
public function prepareColumns(): void
|
||||
{
|
||||
$this->addColumn([
|
||||
'index' => 'id',
|
||||
'label' => trans('admin::app.contacts.organizations.index.datagrid.id'),
|
||||
'type' => 'integer',
|
||||
'filterable' => true,
|
||||
'sortable' => true,
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'name',
|
||||
'label' => trans('admin::app.contacts.organizations.index.datagrid.name'),
|
||||
'type' => 'string',
|
||||
'sortable' => true,
|
||||
'filterable' => true,
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'persons_count',
|
||||
'label' => trans('admin::app.contacts.organizations.index.datagrid.persons-count'),
|
||||
'type' => 'string',
|
||||
'searchable' => false,
|
||||
'sortable' => false,
|
||||
'filterable' => false,
|
||||
'closure' => function ($row) {
|
||||
$personsCount = $this->personRepository->findWhere(['organization_id' => $row->id])->count();
|
||||
|
||||
return $personsCount;
|
||||
},
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'created_at',
|
||||
'label' => trans('admin::app.settings.tags.index.datagrid.created-at'),
|
||||
'type' => 'date',
|
||||
'searchable' => true,
|
||||
'filterable' => true,
|
||||
'filterable_type' => 'date_range',
|
||||
'sortable' => true,
|
||||
'closure' => fn ($row) => core()->formatDate($row->created_at),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare actions.
|
||||
*/
|
||||
public function prepareActions(): void
|
||||
{
|
||||
if (bouncer()->hasPermission('contacts.organizations.edit')) {
|
||||
$this->addAction([
|
||||
'icon' => 'icon-edit',
|
||||
'title' => trans('admin::app.contacts.organizations.index.datagrid.edit'),
|
||||
'method' => 'GET',
|
||||
'url' => fn ($row) => route('admin.contacts.organizations.edit', $row->id),
|
||||
]);
|
||||
}
|
||||
|
||||
if (bouncer()->hasPermission('contacts.organizations.delete')) {
|
||||
$this->addAction([
|
||||
'icon' => 'icon-delete',
|
||||
'title' => trans('admin::app.contacts.organizations.index.datagrid.delete'),
|
||||
'method' => 'DELETE',
|
||||
'url' => fn ($row) => route('admin.contacts.organizations.delete', $row->id),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare mass actions.
|
||||
*/
|
||||
public function prepareMassActions(): void
|
||||
{
|
||||
$this->addMassAction([
|
||||
'icon' => 'icon-delete',
|
||||
'title' => trans('admin::app.contacts.organizations.index.datagrid.delete'),
|
||||
'method' => 'PUT',
|
||||
'url' => route('admin.contacts.organizations.mass_delete'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
160
packages/Webkul/Admin/src/DataGrids/Contact/PersonDataGrid.php
Normal file
160
packages/Webkul/Admin/src/DataGrids/Contact/PersonDataGrid.php
Normal file
@@ -0,0 +1,160 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Admin\DataGrids\Contact;
|
||||
|
||||
use Illuminate\Database\Query\Builder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Webkul\Contact\Repositories\OrganizationRepository;
|
||||
use Webkul\DataGrid\DataGrid;
|
||||
|
||||
class PersonDataGrid extends DataGrid
|
||||
{
|
||||
/**
|
||||
* Create a new class instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(protected OrganizationRepository $organizationRepository) {}
|
||||
|
||||
/**
|
||||
* Prepare query builder.
|
||||
*/
|
||||
public function prepareQueryBuilder(): Builder
|
||||
{
|
||||
$queryBuilder = DB::table('persons')
|
||||
->addSelect(
|
||||
'persons.id',
|
||||
'persons.name as person_name',
|
||||
'persons.emails',
|
||||
'persons.contact_numbers',
|
||||
'organizations.name as organization',
|
||||
'organizations.id as organization_id'
|
||||
)
|
||||
->leftJoin('organizations', 'persons.organization_id', '=', 'organizations.id');
|
||||
|
||||
if ($userIds = bouncer()->getAuthorizedUserIds()) {
|
||||
$queryBuilder->whereIn('persons.user_id', $userIds);
|
||||
}
|
||||
|
||||
$this->addFilter('id', 'persons.id');
|
||||
$this->addFilter('person_name', 'persons.name');
|
||||
$this->addFilter('organization', 'organizations.name');
|
||||
|
||||
return $queryBuilder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add columns.
|
||||
*/
|
||||
public function prepareColumns(): void
|
||||
{
|
||||
$this->addColumn([
|
||||
'index' => 'id',
|
||||
'label' => trans('admin::app.contacts.persons.index.datagrid.id'),
|
||||
'type' => 'integer',
|
||||
'filterable' => true,
|
||||
'sortable' => true,
|
||||
'searchable' => true,
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'person_name',
|
||||
'label' => trans('admin::app.contacts.persons.index.datagrid.name'),
|
||||
'type' => 'string',
|
||||
'sortable' => true,
|
||||
'filterable' => true,
|
||||
'searchable' => true,
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'emails',
|
||||
'label' => trans('admin::app.contacts.persons.index.datagrid.emails'),
|
||||
'type' => 'string',
|
||||
'sortable' => false,
|
||||
'filterable' => true,
|
||||
'searchable' => true,
|
||||
'closure' => fn ($row) => collect(json_decode($row->emails, true) ?? [])->pluck('value')->join(', '),
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'contact_numbers',
|
||||
'label' => trans('admin::app.contacts.persons.index.datagrid.contact-numbers'),
|
||||
'type' => 'string',
|
||||
'sortable' => true,
|
||||
'filterable' => true,
|
||||
'searchable' => true,
|
||||
'closure' => fn ($row) => collect(json_decode($row->contact_numbers, true) ?? [])->pluck('value')->join(', '),
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'organization',
|
||||
'label' => trans('admin::app.contacts.persons.index.datagrid.organization-name'),
|
||||
'type' => 'string',
|
||||
'searchable' => true,
|
||||
'filterable' => true,
|
||||
'sortable' => true,
|
||||
'filterable_type' => 'searchable_dropdown',
|
||||
'filterable_options' => [
|
||||
'repository' => OrganizationRepository::class,
|
||||
'column' => [
|
||||
'label' => 'name',
|
||||
'value' => 'name',
|
||||
],
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare actions.
|
||||
*/
|
||||
public function prepareActions(): void
|
||||
{
|
||||
if (bouncer()->hasPermission('contacts.persons.view')) {
|
||||
$this->addAction([
|
||||
'icon' => 'icon-eye',
|
||||
'title' => trans('admin::app.contacts.persons.index.datagrid.view'),
|
||||
'method' => 'GET',
|
||||
'url' => function ($row) {
|
||||
return route('admin.contacts.persons.view', $row->id);
|
||||
},
|
||||
]);
|
||||
}
|
||||
|
||||
if (bouncer()->hasPermission('contacts.persons.edit')) {
|
||||
$this->addAction([
|
||||
'icon' => 'icon-edit',
|
||||
'title' => trans('admin::app.contacts.persons.index.datagrid.edit'),
|
||||
'method' => 'GET',
|
||||
'url' => function ($row) {
|
||||
return route('admin.contacts.persons.edit', $row->id);
|
||||
},
|
||||
]);
|
||||
}
|
||||
|
||||
if (bouncer()->hasPermission('contacts.persons.delete')) {
|
||||
$this->addAction([
|
||||
'icon' => 'icon-delete',
|
||||
'title' => trans('admin::app.contacts.persons.index.datagrid.delete'),
|
||||
'method' => 'DELETE',
|
||||
'url' => function ($row) {
|
||||
return route('admin.contacts.persons.delete', $row->id);
|
||||
},
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare mass actions.
|
||||
*/
|
||||
public function prepareMassActions(): void
|
||||
{
|
||||
if (bouncer()->hasPermission('contacts.persons.delete')) {
|
||||
$this->addMassAction([
|
||||
'icon' => 'icon-delete',
|
||||
'title' => trans('admin::app.contacts.persons.index.datagrid.delete'),
|
||||
'method' => 'POST',
|
||||
'url' => route('admin.contacts.persons.mass_delete'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
326
packages/Webkul/Admin/src/DataGrids/Lead/LeadDataGrid.php
Normal file
326
packages/Webkul/Admin/src/DataGrids/Lead/LeadDataGrid.php
Normal file
@@ -0,0 +1,326 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Admin\DataGrids\Lead;
|
||||
|
||||
use Illuminate\Contracts\Database\Query\Builder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Webkul\DataGrid\DataGrid;
|
||||
use Webkul\Lead\Repositories\PipelineRepository;
|
||||
use Webkul\Lead\Repositories\SourceRepository;
|
||||
use Webkul\Lead\Repositories\StageRepository;
|
||||
use Webkul\Lead\Repositories\TypeRepository;
|
||||
use Webkul\Tag\Repositories\TagRepository;
|
||||
use Webkul\User\Repositories\UserRepository;
|
||||
|
||||
class LeadDataGrid extends DataGrid
|
||||
{
|
||||
/**
|
||||
* Pipeline instance.
|
||||
*
|
||||
* @var \Webkul\Contract\Repositories\Pipeline
|
||||
*/
|
||||
protected $pipeline;
|
||||
|
||||
/**
|
||||
* Create data grid instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(
|
||||
protected PipelineRepository $pipelineRepository,
|
||||
protected StageRepository $stageRepository,
|
||||
protected SourceRepository $sourceRepository,
|
||||
protected TypeRepository $typeRepository,
|
||||
protected UserRepository $userRepository,
|
||||
protected TagRepository $tagRepository,
|
||||
) {
|
||||
if (request('pipeline_id')) {
|
||||
$this->pipeline = $this->pipelineRepository->find(request('pipeline_id'));
|
||||
} else {
|
||||
$this->pipeline = $this->pipelineRepository->getDefaultPipeline();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare query builder.
|
||||
*/
|
||||
public function prepareQueryBuilder(): Builder
|
||||
{
|
||||
$tablePrefix = DB::getTablePrefix();
|
||||
|
||||
$queryBuilder = DB::table('leads')
|
||||
->addSelect(
|
||||
'leads.id',
|
||||
'leads.title',
|
||||
'leads.status',
|
||||
'leads.lead_value',
|
||||
'leads.expected_close_date',
|
||||
'lead_sources.name as lead_source_name',
|
||||
'lead_types.name as lead_type_name',
|
||||
'leads.created_at',
|
||||
'lead_pipeline_stages.name as stage',
|
||||
'lead_tags.tag_id as tag_id',
|
||||
'users.id as user_id',
|
||||
'users.name as sales_person',
|
||||
'persons.id as person_id',
|
||||
'persons.name as person_name',
|
||||
'tags.name as tag_name',
|
||||
'lead_pipelines.rotten_days as pipeline_rotten_days',
|
||||
'lead_pipeline_stages.code as stage_code',
|
||||
DB::raw('CASE WHEN DATEDIFF(NOW(),'.$tablePrefix.'leads.created_at) >='.$tablePrefix.'lead_pipelines.rotten_days THEN 1 ELSE 0 END as rotten_lead'),
|
||||
)
|
||||
->leftJoin('users', 'leads.user_id', '=', 'users.id')
|
||||
->leftJoin('persons', 'leads.person_id', '=', 'persons.id')
|
||||
->leftJoin('lead_types', 'leads.lead_type_id', '=', 'lead_types.id')
|
||||
->leftJoin('lead_pipeline_stages', 'leads.lead_pipeline_stage_id', '=', 'lead_pipeline_stages.id')
|
||||
->leftJoin('lead_sources', 'leads.lead_source_id', '=', 'lead_sources.id')
|
||||
->leftJoin('lead_pipelines', 'leads.lead_pipeline_id', '=', 'lead_pipelines.id')
|
||||
->leftJoin('lead_tags', 'leads.id', '=', 'lead_tags.lead_id')
|
||||
->leftJoin('tags', 'tags.id', '=', 'lead_tags.tag_id')
|
||||
->groupBy('leads.id')
|
||||
->where('leads.lead_pipeline_id', $this->pipeline->id);
|
||||
|
||||
if ($userIds = bouncer()->getAuthorizedUserIds()) {
|
||||
$queryBuilder->whereIn('leads.user_id', $userIds);
|
||||
}
|
||||
|
||||
if (! is_null(request()->input('rotten_lead.in'))) {
|
||||
$queryBuilder->havingRaw($tablePrefix.'rotten_lead = '.request()->input('rotten_lead.in'));
|
||||
}
|
||||
|
||||
$this->addFilter('id', 'leads.id');
|
||||
$this->addFilter('user', 'leads.user_id');
|
||||
$this->addFilter('sales_person', 'users.name');
|
||||
$this->addFilter('lead_source_name', 'lead_sources.id');
|
||||
$this->addFilter('lead_type_name', 'lead_types.id');
|
||||
$this->addFilter('person_name', 'persons.name');
|
||||
$this->addFilter('type', 'lead_pipeline_stages.code');
|
||||
$this->addFilter('stage', 'lead_pipeline_stages.id');
|
||||
$this->addFilter('tag_name', 'tags.name');
|
||||
$this->addFilter('expected_close_date', 'leads.expected_close_date');
|
||||
$this->addFilter('created_at', 'leads.created_at');
|
||||
$this->addFilter('rotten_lead', DB::raw('DATEDIFF(NOW(), '.$tablePrefix.'leads.created_at) >= '.$tablePrefix.'lead_pipelines.rotten_days'));
|
||||
|
||||
return $queryBuilder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare columns.
|
||||
*/
|
||||
public function prepareColumns(): void
|
||||
{
|
||||
$this->addColumn([
|
||||
'index' => 'id',
|
||||
'label' => trans('admin::app.leads.index.datagrid.id'),
|
||||
'type' => 'integer',
|
||||
'sortable' => true,
|
||||
'filterable' => true,
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'sales_person',
|
||||
'label' => trans('admin::app.leads.index.datagrid.sales-person'),
|
||||
'type' => 'string',
|
||||
'searchable' => false,
|
||||
'sortable' => true,
|
||||
'filterable' => true,
|
||||
'filterable_type' => 'searchable_dropdown',
|
||||
'filterable_options' => [
|
||||
'repository' => UserRepository::class,
|
||||
'column' => [
|
||||
'label' => 'name',
|
||||
'value' => 'name',
|
||||
],
|
||||
],
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'title',
|
||||
'label' => trans('admin::app.leads.index.datagrid.subject'),
|
||||
'type' => 'string',
|
||||
'searchable' => true,
|
||||
'sortable' => true,
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'lead_source_name',
|
||||
'label' => trans('admin::app.leads.index.datagrid.source'),
|
||||
'type' => 'string',
|
||||
'searchable' => false,
|
||||
'sortable' => true,
|
||||
'filterable' => true,
|
||||
'filterable_type' => 'dropdown',
|
||||
'filterable_options' => $this->sourceRepository->all(['name as label', 'id as value'])->toArray(),
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'lead_value',
|
||||
'label' => trans('admin::app.leads.index.datagrid.lead-value'),
|
||||
'type' => 'string',
|
||||
'sortable' => true,
|
||||
'searchable' => false,
|
||||
'filterable' => true,
|
||||
'closure' => fn ($row) => core()->formatBasePrice($row->lead_value, 2),
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'lead_type_name',
|
||||
'label' => trans('admin::app.leads.index.datagrid.lead-type'),
|
||||
'type' => 'string',
|
||||
'searchable' => false,
|
||||
'sortable' => true,
|
||||
'filterable' => true,
|
||||
'filterable_type' => 'dropdown',
|
||||
'filterable_options' => $this->typeRepository->all(['name as label', 'id as value'])->toArray(),
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'tag_name',
|
||||
'label' => trans('admin::app.leads.index.datagrid.tag-name'),
|
||||
'type' => 'string',
|
||||
'searchable' => false,
|
||||
'sortable' => true,
|
||||
'filterable' => true,
|
||||
'filterable_type' => 'searchable_dropdown',
|
||||
'closure' => fn ($row) => $row->tag_name ?? '--',
|
||||
'filterable_options' => [
|
||||
'repository' => TagRepository::class,
|
||||
'column' => [
|
||||
'label' => 'name',
|
||||
'value' => 'name',
|
||||
],
|
||||
],
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'person_name',
|
||||
'label' => trans('admin::app.leads.index.datagrid.contact-person'),
|
||||
'type' => 'string',
|
||||
'searchable' => false,
|
||||
'sortable' => true,
|
||||
'filterable' => true,
|
||||
'filterable_type' => 'searchable_dropdown',
|
||||
'filterable_options' => [
|
||||
'repository' => \Webkul\Contact\Repositories\PersonRepository::class,
|
||||
'column' => [
|
||||
'label' => 'name',
|
||||
'value' => 'name',
|
||||
],
|
||||
],
|
||||
'closure' => function ($row) {
|
||||
$route = route('admin.contacts.persons.view', $row->person_id);
|
||||
|
||||
return "<a class=\"text-brandColor transition-all hover:underline\" href='".$route."'>".$row->person_name.'</a>';
|
||||
},
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'stage',
|
||||
'label' => trans('admin::app.leads.index.datagrid.stage'),
|
||||
'type' => 'string',
|
||||
'searchable' => false,
|
||||
'sortable' => true,
|
||||
'filterable' => true,
|
||||
'filterable_type' => 'dropdown',
|
||||
'filterable_options' => $this->pipeline->stages->pluck('name', 'id')
|
||||
->map(function ($name, $id) {
|
||||
return ['value' => $id, 'label' => $name];
|
||||
})
|
||||
->values()
|
||||
->all(),
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'rotten_lead',
|
||||
'label' => trans('admin::app.leads.index.datagrid.rotten-lead'),
|
||||
'type' => 'string',
|
||||
'sortable' => true,
|
||||
'searchable' => false,
|
||||
'closure' => function ($row) {
|
||||
if (! $row->rotten_lead) {
|
||||
return trans('admin::app.leads.index.datagrid.no');
|
||||
}
|
||||
|
||||
if (in_array($row->stage_code, ['won', 'lost'])) {
|
||||
return trans('admin::app.leads.index.datagrid.no');
|
||||
}
|
||||
|
||||
return trans('admin::app.leads.index.datagrid.yes');
|
||||
},
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'expected_close_date',
|
||||
'label' => trans('admin::app.leads.index.datagrid.date-to'),
|
||||
'type' => 'date',
|
||||
'searchable' => false,
|
||||
'sortable' => true,
|
||||
'filterable' => true,
|
||||
'filterable_type' => 'date_range',
|
||||
'closure' => function ($row) {
|
||||
if (! $row->expected_close_date) {
|
||||
return '--';
|
||||
}
|
||||
|
||||
return $row->expected_close_date;
|
||||
},
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'created_at',
|
||||
'label' => trans('admin::app.leads.index.datagrid.created-at'),
|
||||
'type' => 'date',
|
||||
'searchable' => false,
|
||||
'sortable' => true,
|
||||
'filterable' => true,
|
||||
'filterable_type' => 'date_range',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare actions.
|
||||
*/
|
||||
public function prepareActions(): void
|
||||
{
|
||||
if (bouncer()->hasPermission('leads.view')) {
|
||||
$this->addAction([
|
||||
'icon' => 'icon-eye',
|
||||
'title' => trans('admin::app.leads.index.datagrid.view'),
|
||||
'method' => 'GET',
|
||||
'url' => fn ($row) => route('admin.leads.view', $row->id),
|
||||
]);
|
||||
}
|
||||
|
||||
if (bouncer()->hasPermission('leads.delete')) {
|
||||
$this->addAction([
|
||||
'icon' => 'icon-delete',
|
||||
'title' => trans('admin::app.leads.index.datagrid.delete'),
|
||||
'method' => 'delete',
|
||||
'url' => fn ($row) => route('admin.leads.delete', $row->id),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare mass actions.
|
||||
*/
|
||||
public function prepareMassActions(): void
|
||||
{
|
||||
$this->addMassAction([
|
||||
'icon' => 'icon-delete',
|
||||
'title' => trans('admin::app.leads.index.datagrid.mass-delete'),
|
||||
'method' => 'POST',
|
||||
'url' => route('admin.leads.mass_delete'),
|
||||
]);
|
||||
|
||||
$this->addMassAction([
|
||||
'title' => trans('admin::app.leads.index.datagrid.mass-update'),
|
||||
'url' => route('admin.leads.mass_update'),
|
||||
'method' => 'POST',
|
||||
'options' => $this->pipeline->stages->map(fn ($stage) => [
|
||||
'label' => $stage->name,
|
||||
'value' => $stage->id,
|
||||
])->toArray(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
212
packages/Webkul/Admin/src/DataGrids/Mail/EmailDataGrid.php
Normal file
212
packages/Webkul/Admin/src/DataGrids/Mail/EmailDataGrid.php
Normal file
@@ -0,0 +1,212 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Admin\DataGrids\Mail;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Database\Query\Builder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Webkul\DataGrid\DataGrid;
|
||||
use Webkul\Email\Repositories\EmailRepository;
|
||||
use Webkul\Tag\Repositories\TagRepository;
|
||||
|
||||
class EmailDataGrid extends DataGrid
|
||||
{
|
||||
/**
|
||||
* Default sort column of datagrid.
|
||||
*
|
||||
* @var ?string
|
||||
*/
|
||||
protected $sortColumn = 'created_at';
|
||||
|
||||
/**
|
||||
* Prepare query builder.
|
||||
*/
|
||||
public function prepareQueryBuilder(): Builder
|
||||
{
|
||||
$queryBuilder = DB::table('emails')
|
||||
->select(
|
||||
'emails.id',
|
||||
'emails.name',
|
||||
'emails.from',
|
||||
'emails.subject',
|
||||
'emails.reply',
|
||||
'emails.is_read',
|
||||
'emails.created_at',
|
||||
'tags.name as tags',
|
||||
DB::raw('COUNT(DISTINCT '.DB::getTablePrefix().'email_attachments.id) as attachments')
|
||||
)
|
||||
->leftJoin('email_attachments', 'emails.id', '=', 'email_attachments.email_id')
|
||||
->leftJoin('email_tags', 'emails.id', '=', 'email_tags.email_id')
|
||||
->leftJoin('tags', 'tags.id', '=', 'email_tags.tag_id')
|
||||
->groupBy('emails.id')
|
||||
->where('folders', 'like', '%"'.request('route').'"%')
|
||||
->whereNull('parent_id');
|
||||
|
||||
$this->addFilter('id', 'emails.id');
|
||||
$this->addFilter('name', 'emails.name');
|
||||
$this->addFilter('tags', 'tags.name');
|
||||
$this->addFilter('created_at', 'emails.created_at');
|
||||
|
||||
return $queryBuilder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare Columns.
|
||||
*/
|
||||
public function prepareColumns(): void
|
||||
{
|
||||
$this->addColumn([
|
||||
'index' => 'attachments',
|
||||
'label' => trans('admin::app.mail.index.datagrid.attachments'),
|
||||
'type' => 'string',
|
||||
'searchable' => false,
|
||||
'filterable' => false,
|
||||
'sortable' => false,
|
||||
'closure' => fn ($row) => $row->attachments ? '<i class="icon-attachment text-2xl"></i>' : '',
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'name',
|
||||
'label' => trans('admin::app.mail.index.datagrid.from'),
|
||||
'type' => 'string',
|
||||
'sortable' => true,
|
||||
'searchable' => true,
|
||||
'filterable' => true,
|
||||
'closure' => function ($row) {
|
||||
return $row->name
|
||||
? trim($row->name, '"')
|
||||
: trim($row->from, '"');
|
||||
},
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'subject',
|
||||
'label' => trans('admin::app.mail.index.datagrid.subject'),
|
||||
'type' => 'string',
|
||||
'sortable' => true,
|
||||
'searchable' => true,
|
||||
'filterable' => true,
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'reply',
|
||||
'label' => trans('admin::app.mail.index.datagrid.content'),
|
||||
'type' => 'string',
|
||||
'sortable' => true,
|
||||
'searchable' => true,
|
||||
'filterable' => true,
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'tags',
|
||||
'label' => trans('admin::app.mail.index.datagrid.tags'),
|
||||
'type' => 'string',
|
||||
'searchable' => false,
|
||||
'sortable' => true,
|
||||
'filterable' => true,
|
||||
'filterable_type' => 'searchable_dropdown',
|
||||
'closure' => function ($row) {
|
||||
if ($email = app(EmailRepository::class)->find($row->id)) {
|
||||
return $email->tags;
|
||||
}
|
||||
|
||||
return '--';
|
||||
},
|
||||
'filterable_options' => [
|
||||
'repository' => TagRepository::class,
|
||||
'column' => [
|
||||
'label' => 'name',
|
||||
'value' => 'name',
|
||||
],
|
||||
],
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'created_at',
|
||||
'label' => trans('admin::app.mail.index.datagrid.date'),
|
||||
'type' => 'date',
|
||||
'searchable' => true,
|
||||
'filterable' => true,
|
||||
'filterable_type' => 'date_range',
|
||||
'sortable' => true,
|
||||
'closure' => function ($row) {
|
||||
return Carbon::parse($row->created_at)->isToday()
|
||||
? Carbon::parse($row->created_at)->format('h:i A')
|
||||
: Carbon::parse($row->created_at)->format('M d');
|
||||
},
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare actions.
|
||||
*/
|
||||
public function prepareActions(): void
|
||||
{
|
||||
if (bouncer()->hasPermission('mail.view')) {
|
||||
$this->addAction([
|
||||
'index' => 'edit',
|
||||
'icon' => request('route') == 'draft'
|
||||
? 'icon-edit'
|
||||
: 'icon-eye',
|
||||
'title' => request('route') == 'draft'
|
||||
? trans('admin::app.mail.index.datagrid.edit')
|
||||
: trans('admin::app.mail.index.datagrid.view'),
|
||||
'method' => 'GET',
|
||||
'params' => [
|
||||
'type' => request('route') == 'trash'
|
||||
? 'delete'
|
||||
: 'trash',
|
||||
],
|
||||
'url' => fn ($row) => route('admin.mail.view', [request('route'), $row->id]),
|
||||
]);
|
||||
}
|
||||
|
||||
if (bouncer()->hasPermission('mail.delete')) {
|
||||
$this->addAction([
|
||||
'index' => 'delete',
|
||||
'icon' => 'icon-delete',
|
||||
'title' => trans('admin::app.mail.index.datagrid.delete'),
|
||||
'method' => 'DELETE',
|
||||
'params' => [
|
||||
'type' => request('route') == 'trash'
|
||||
? 'delete'
|
||||
: 'trash',
|
||||
],
|
||||
'url' => fn ($row) => route('admin.mail.delete', $row->id),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare mass actions.
|
||||
*/
|
||||
public function prepareMassActions(): void
|
||||
{
|
||||
if (request('route') == 'trash') {
|
||||
$this->addMassAction([
|
||||
'title' => trans('admin::app.mail.index.datagrid.move-to-inbox'),
|
||||
'method' => 'POST',
|
||||
'url' => route('admin.mail.mass_update', ['folders' => ['inbox']]),
|
||||
'options' => [
|
||||
[
|
||||
'value' => 'trash',
|
||||
'label' => trans('admin::app.mail.index.datagrid.move-to-inbox'),
|
||||
],
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
$this->addMassAction([
|
||||
'icon' => 'icon-delete',
|
||||
'title' => request('route') == 'trash'
|
||||
? trans('admin::app.mail.index.datagrid.delete')
|
||||
: trans('admin::app.mail.index.datagrid.move-to-trash'),
|
||||
'method' => 'POST',
|
||||
'url' => route('admin.mail.mass_delete', [
|
||||
'type' => request('route') == 'trash'
|
||||
? 'delete'
|
||||
: 'trash',
|
||||
]),
|
||||
]);
|
||||
}
|
||||
}
|
||||
169
packages/Webkul/Admin/src/DataGrids/Product/ProductDataGrid.php
Normal file
169
packages/Webkul/Admin/src/DataGrids/Product/ProductDataGrid.php
Normal file
@@ -0,0 +1,169 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Admin\DataGrids\Product;
|
||||
|
||||
use Illuminate\Database\Query\Builder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Webkul\DataGrid\DataGrid;
|
||||
use Webkul\Tag\Repositories\TagRepository;
|
||||
|
||||
class ProductDataGrid extends DataGrid
|
||||
{
|
||||
/**
|
||||
* Prepare query builder.
|
||||
*/
|
||||
public function prepareQueryBuilder(): Builder
|
||||
{
|
||||
$tablePrefix = DB::getTablePrefix();
|
||||
|
||||
$queryBuilder = DB::table('products')
|
||||
->leftJoin('product_inventories', 'products.id', '=', 'product_inventories.product_id')
|
||||
->leftJoin('product_tags', 'products.id', '=', 'product_tags.product_id')
|
||||
->leftJoin('tags', 'tags.id', '=', 'product_tags.tag_id')
|
||||
->select(
|
||||
'products.id',
|
||||
'products.sku',
|
||||
'products.name',
|
||||
'products.price',
|
||||
'tags.name as tag_name',
|
||||
)
|
||||
->addSelect(DB::raw('SUM('.$tablePrefix.'product_inventories.in_stock) as total_in_stock'))
|
||||
->addSelect(DB::raw('SUM('.$tablePrefix.'product_inventories.allocated) as total_allocated'))
|
||||
->addSelect(DB::raw('SUM('.$tablePrefix.'product_inventories.in_stock - '.$tablePrefix.'product_inventories.allocated) as total_on_hand'))
|
||||
->groupBy('products.id');
|
||||
|
||||
if (request()->route('id')) {
|
||||
$queryBuilder->where('product_inventories.warehouse_id', request()->route('id'));
|
||||
}
|
||||
|
||||
$this->addFilter('id', 'products.id');
|
||||
$this->addFilter('total_in_stock', DB::raw('SUM('.$tablePrefix.'product_inventories.in_stock'));
|
||||
$this->addFilter('total_allocated', DB::raw('SUM('.$tablePrefix.'product_inventories.allocated'));
|
||||
$this->addFilter('total_on_hand', DB::raw('SUM('.$tablePrefix.'product_inventories.in_stock - '.$tablePrefix.'product_inventories.allocated'));
|
||||
$this->addFilter('tag_name', 'tags.name');
|
||||
|
||||
return $queryBuilder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add columns.
|
||||
*/
|
||||
public function prepareColumns(): void
|
||||
{
|
||||
$this->addColumn([
|
||||
'index' => 'sku',
|
||||
'label' => trans('admin::app.products.index.datagrid.sku'),
|
||||
'type' => 'string',
|
||||
'sortable' => true,
|
||||
'searchable' => true,
|
||||
'filterable' => true,
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'name',
|
||||
'label' => trans('admin::app.products.index.datagrid.name'),
|
||||
'type' => 'string',
|
||||
'sortable' => true,
|
||||
'searchable' => true,
|
||||
'filterable' => true,
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'price',
|
||||
'label' => trans('admin::app.products.index.datagrid.price'),
|
||||
'type' => 'string',
|
||||
'sortable' => true,
|
||||
'searchable' => true,
|
||||
'filterable' => true,
|
||||
'closure' => fn ($row) => round($row->price, 2),
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'total_in_stock',
|
||||
'label' => trans('admin::app.products.index.datagrid.in-stock'),
|
||||
'type' => 'string',
|
||||
'sortable' => true,
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'total_allocated',
|
||||
'label' => trans('admin::app.products.index.datagrid.allocated'),
|
||||
'type' => 'string',
|
||||
'sortable' => true,
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'total_on_hand',
|
||||
'label' => trans('admin::app.products.index.datagrid.on-hand'),
|
||||
'type' => 'string',
|
||||
'sortable' => true,
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'tag_name',
|
||||
'label' => trans('admin::app.products.index.datagrid.tag-name'),
|
||||
'type' => 'string',
|
||||
'searchable' => false,
|
||||
'sortable' => true,
|
||||
'filterable' => true,
|
||||
'filterable_type' => 'searchable_dropdown',
|
||||
'closure' => fn ($row) => $row->tag_name ?? '--',
|
||||
'filterable_options' => [
|
||||
'repository' => TagRepository::class,
|
||||
'column' => [
|
||||
'label' => 'name',
|
||||
'value' => 'name',
|
||||
],
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare actions.
|
||||
*/
|
||||
public function prepareActions(): void
|
||||
{
|
||||
if (bouncer()->hasPermission('products.view')) {
|
||||
$this->addAction([
|
||||
'index' => 'view',
|
||||
'icon' => 'icon-eye',
|
||||
'title' => trans('admin::app.products.index.datagrid.view'),
|
||||
'method' => 'GET',
|
||||
'url' => fn ($row) => route('admin.products.view', $row->id),
|
||||
]);
|
||||
}
|
||||
|
||||
if (bouncer()->hasPermission('products.edit')) {
|
||||
$this->addAction([
|
||||
'index' => 'edit',
|
||||
'icon' => 'icon-edit',
|
||||
'title' => trans('admin::app.products.index.datagrid.edit'),
|
||||
'method' => 'GET',
|
||||
'url' => fn ($row) => route('admin.products.edit', $row->id),
|
||||
]);
|
||||
}
|
||||
|
||||
if (bouncer()->hasPermission('products.delete')) {
|
||||
$this->addAction([
|
||||
'index' => 'delete',
|
||||
'icon' => 'icon-delete',
|
||||
'title' => trans('admin::app.products.index.datagrid.delete'),
|
||||
'method' => 'DELETE',
|
||||
'url' => fn ($row) => route('admin.products.delete', $row->id),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare mass actions.
|
||||
*/
|
||||
public function prepareMassActions(): void
|
||||
{
|
||||
$this->addMassAction([
|
||||
'icon' => 'icon-delete',
|
||||
'title' => trans('admin::app.products.index.datagrid.delete'),
|
||||
'method' => 'POST',
|
||||
'url' => route('admin.products.mass_delete'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
229
packages/Webkul/Admin/src/DataGrids/Quote/QuoteDataGrid.php
Normal file
229
packages/Webkul/Admin/src/DataGrids/Quote/QuoteDataGrid.php
Normal file
@@ -0,0 +1,229 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Admin\DataGrids\Quote;
|
||||
|
||||
use Illuminate\Database\Query\Builder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Webkul\DataGrid\DataGrid;
|
||||
|
||||
class QuoteDataGrid extends DataGrid
|
||||
{
|
||||
/**
|
||||
* Prepare query builder.
|
||||
*/
|
||||
public function prepareQueryBuilder(): Builder
|
||||
{
|
||||
$tablePrefix = DB::getTablePrefix();
|
||||
|
||||
$queryBuilder = DB::table('quotes')
|
||||
->addSelect(
|
||||
'quotes.id',
|
||||
'quotes.subject',
|
||||
'quotes.expired_at',
|
||||
'quotes.sub_total',
|
||||
'quotes.discount_amount',
|
||||
'quotes.tax_amount',
|
||||
'quotes.adjustment_amount',
|
||||
'quotes.grand_total',
|
||||
'quotes.created_at',
|
||||
'users.id as user_id',
|
||||
'users.name as sales_person',
|
||||
'persons.id as person_id',
|
||||
'persons.name as person_name',
|
||||
'quotes.expired_at as expired_quotes'
|
||||
)
|
||||
->leftJoin('users', 'quotes.user_id', '=', 'users.id')
|
||||
->leftJoin('persons', 'quotes.person_id', '=', 'persons.id');
|
||||
|
||||
if ($userIds = bouncer()->getAuthorizedUserIds()) {
|
||||
$queryBuilder->whereIn('quotes.user_id', $userIds);
|
||||
}
|
||||
|
||||
$this->addFilter('id', 'quotes.id');
|
||||
$this->addFilter('user', 'quotes.user_id');
|
||||
$this->addFilter('sales_person', 'users.name');
|
||||
$this->addFilter('person_name', 'persons.name');
|
||||
$this->addFilter('expired_at', 'quotes.expired_at');
|
||||
$this->addFilter('created_at', 'quotes.created_at');
|
||||
|
||||
if (request()->input('expired_quotes.in') == 1) {
|
||||
$this->addFilter('expired_quotes', DB::raw('DATEDIFF(NOW(), '.$tablePrefix.'quotes.expired_at) >= '.$tablePrefix.'NOW()'));
|
||||
} else {
|
||||
$this->addFilter('expired_quotes', DB::raw('DATEDIFF(NOW(), '.$tablePrefix.'quotes.expired_at) < '.$tablePrefix.'NOW()'));
|
||||
}
|
||||
|
||||
return $queryBuilder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare columns.
|
||||
*/
|
||||
public function prepareColumns(): void
|
||||
{
|
||||
$this->addColumn([
|
||||
'index' => 'subject',
|
||||
'label' => trans('admin::app.quotes.index.datagrid.subject'),
|
||||
'type' => 'string',
|
||||
'filterable' => true,
|
||||
'sortable' => true,
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'sales_person',
|
||||
'label' => trans('admin::app.quotes.index.datagrid.sales-person'),
|
||||
'type' => 'string',
|
||||
'sortable' => true,
|
||||
'filterable' => true,
|
||||
'filterable_type' => 'searchable_dropdown',
|
||||
'filterable_options' => [
|
||||
'repository' => \Webkul\User\Repositories\UserRepository::class,
|
||||
'column' => [
|
||||
'label' => 'name',
|
||||
'value' => 'name',
|
||||
],
|
||||
],
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'person_name',
|
||||
'label' => trans('admin::app.quotes.index.datagrid.person'),
|
||||
'type' => 'string',
|
||||
'sortable' => true,
|
||||
'filterable' => true,
|
||||
'filterable_type' => 'searchable_dropdown',
|
||||
'filterable_options' => [
|
||||
'repository' => \Webkul\Contact\Repositories\PersonRepository::class,
|
||||
'column' => [
|
||||
'label' => 'name',
|
||||
'value' => 'name',
|
||||
],
|
||||
],
|
||||
'closure' => function ($row) {
|
||||
$route = route('admin.contacts.persons.view', $row->person_id);
|
||||
|
||||
return "<a class=\"text-brandColor transition-all hover:underline\" href='".$route."'>".$row->person_name.'</a>';
|
||||
},
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'sub_total',
|
||||
'label' => trans('admin::app.quotes.index.datagrid.subtotal'),
|
||||
'type' => 'string',
|
||||
'sortable' => true,
|
||||
'filterable' => true,
|
||||
'closure' => fn ($row) => core()->formatBasePrice($row->sub_total, 2),
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'discount_amount',
|
||||
'label' => trans('admin::app.quotes.index.datagrid.discount'),
|
||||
'type' => 'string',
|
||||
'sortable' => true,
|
||||
'filterable' => true,
|
||||
'closure' => fn ($row) => core()->formatBasePrice($row->discount_amount, 2),
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'tax_amount',
|
||||
'label' => trans('admin::app.quotes.index.datagrid.tax'),
|
||||
'type' => 'string',
|
||||
'filterable' => true,
|
||||
'sortable' => true,
|
||||
'closure' => fn ($row) => core()->formatBasePrice($row->tax_amount, 2),
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'adjustment_amount',
|
||||
'label' => trans('admin::app.quotes.index.datagrid.adjustment'),
|
||||
'type' => 'string',
|
||||
'sortable' => true,
|
||||
'filterable' => false,
|
||||
'closure' => fn ($row) => core()->formatBasePrice($row->adjustment_amount, 2),
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'grand_total',
|
||||
'label' => trans('admin::app.quotes.index.datagrid.grand-total'),
|
||||
'type' => 'string',
|
||||
'sortable' => true,
|
||||
'filterable' => true,
|
||||
'closure' => fn ($row) => core()->formatBasePrice($row->grand_total, 2),
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'expired_at',
|
||||
'label' => trans('admin::app.quotes.index.datagrid.expired-at'),
|
||||
'type' => 'date',
|
||||
'searchable' => false,
|
||||
'sortable' => true,
|
||||
'filterable' => true,
|
||||
'closure' => fn ($row) => core()->formatDate($row->expired_at, 'd M Y'),
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'created_at',
|
||||
'label' => trans('admin::app.quotes.index.datagrid.created-at'),
|
||||
'type' => 'date',
|
||||
'searchable' => false,
|
||||
'sortable' => true,
|
||||
'filterable' => true,
|
||||
'closure' => fn ($row) => core()->formatDate($row->created_at),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare actions.
|
||||
*/
|
||||
public function prepareActions(): void
|
||||
{
|
||||
if (bouncer()->hasPermission('quotes.edit')) {
|
||||
$this->addAction([
|
||||
'index' => 'edit',
|
||||
'icon' => 'icon-edit',
|
||||
'title' => trans('admin::app.quotes.index.datagrid.edit'),
|
||||
'method' => 'GET',
|
||||
'url' => fn ($row) => route('admin.quotes.edit', $row->id),
|
||||
]);
|
||||
}
|
||||
|
||||
if (bouncer()->hasPermission('quotes.print')) {
|
||||
$this->addAction([
|
||||
'index' => 'print',
|
||||
'icon' => 'icon-print',
|
||||
'title' => trans('admin::app.quotes.index.datagrid.print'),
|
||||
'method' => 'GET',
|
||||
'url' => fn ($row) => route('admin.quotes.print', $row->id),
|
||||
]);
|
||||
}
|
||||
|
||||
if (bouncer()->hasPermission('quotes.delete')) {
|
||||
$this->addAction([
|
||||
'index' => 'delete',
|
||||
'icon' => 'icon-delete',
|
||||
'title' => trans('admin::app.quotes.index.datagrid.delete'),
|
||||
'method' => 'DELETE',
|
||||
'url' => fn ($row) => route('admin.quotes.delete', $row->id),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare mass actions.
|
||||
*/
|
||||
public function prepareMassActions(): void
|
||||
{
|
||||
$this->addMassAction([
|
||||
'icon' => 'icon-delete',
|
||||
'title' => trans('admin::app.quotes.index.datagrid.delete'),
|
||||
'method' => 'POST',
|
||||
'url' => route('admin.quotes.mass_delete'),
|
||||
]);
|
||||
|
||||
$this->addMassAction([
|
||||
'icon' => 'icon-delete',
|
||||
'title' => trans('admin::app.quotes.index.datagrid.delete'),
|
||||
'method' => 'POST',
|
||||
'url' => route('admin.quotes.mass_delete'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Admin\DataGrids\Settings;
|
||||
|
||||
use Illuminate\Database\Query\Builder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Webkul\Attribute\Repositories\AttributeRepository;
|
||||
use Webkul\DataGrid\DataGrid;
|
||||
|
||||
class AttributeDataGrid extends DataGrid
|
||||
{
|
||||
/**
|
||||
* Prepare query builder.
|
||||
*/
|
||||
public function prepareQueryBuilder(): Builder
|
||||
{
|
||||
$queryBuilder = DB::table('attributes')
|
||||
->select(
|
||||
'attributes.id',
|
||||
'attributes.code',
|
||||
'attributes.name',
|
||||
'attributes.type',
|
||||
'attributes.entity_type',
|
||||
'attributes.is_user_defined as attribute_type'
|
||||
)
|
||||
->where('entity_type', '<>', 'locations');
|
||||
|
||||
$this->addFilter('id', 'attributes.id');
|
||||
$this->addFilter('type', 'attributes.type');
|
||||
$this->addFilter('attribute_type', 'attributes.is_user_defined');
|
||||
|
||||
return $queryBuilder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare columns.
|
||||
*/
|
||||
public function prepareColumns(): void
|
||||
{
|
||||
$this->addColumn([
|
||||
'index' => 'id',
|
||||
'label' => trans('admin::app.settings.attributes.index.datagrid.id'),
|
||||
'type' => 'string',
|
||||
'filterable' => true,
|
||||
'sortable' => true,
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'code',
|
||||
'label' => trans('admin::app.settings.attributes.index.datagrid.code'),
|
||||
'type' => 'string',
|
||||
'sortable' => true,
|
||||
'searchable' => true,
|
||||
'filterable' => true,
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'name',
|
||||
'label' => trans('admin::app.settings.attributes.index.datagrid.name'),
|
||||
'type' => 'string',
|
||||
'sortable' => true,
|
||||
'searchable' => true,
|
||||
'filterable' => true,
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'entity_type',
|
||||
'label' => trans('admin::app.settings.attributes.index.datagrid.entity-type'),
|
||||
'type' => 'string',
|
||||
'sortable' => true,
|
||||
'searchable' => false,
|
||||
'filterable' => true,
|
||||
'filterable_type' => 'dropdown',
|
||||
'filterable_options' => app(AttributeRepository::class)
|
||||
->select('entity_type as label', 'entity_type as value')
|
||||
->distinct()
|
||||
->get()
|
||||
->map(function ($item) {
|
||||
$item->label = trans('admin::app.settings.attributes.index.datagrid.entity-types.'.$item->label);
|
||||
|
||||
return $item;
|
||||
})
|
||||
->toArray(),
|
||||
'closure' => fn ($row) => ucfirst($row->entity_type),
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'type',
|
||||
'label' => trans('admin::app.settings.attributes.index.datagrid.type'),
|
||||
'type' => 'string',
|
||||
'sortable' => true,
|
||||
'filterable' => true,
|
||||
'filterable_type' => 'dropdown',
|
||||
'filterable_options' => app(AttributeRepository::class)
|
||||
->select('type as label', 'type as value')
|
||||
->distinct()
|
||||
->get()
|
||||
->map(function ($item) {
|
||||
$item->label = trans('admin::app.settings.attributes.index.datagrid.types.'.$item->label);
|
||||
|
||||
return $item;
|
||||
})
|
||||
->toArray(),
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'attribute_type',
|
||||
'label' => trans('admin::app.settings.attributes.index.datagrid.is-default'),
|
||||
'type' => 'boolean',
|
||||
'searchable' => true,
|
||||
'filterable' => false,
|
||||
'sortable' => true,
|
||||
'closure' => fn ($value) => trans('admin::app.settings.attributes.index.datagrid.'.($value->attribute_type ? 'no' : 'yes')),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare actions.
|
||||
*/
|
||||
public function prepareActions(): void
|
||||
{
|
||||
if (bouncer()->hasPermission('settings.automation.attributes.edit')) {
|
||||
$this->addAction([
|
||||
'icon' => 'icon-edit',
|
||||
'title' => trans('admin::app.settings.attributes.index.datagrid.edit'),
|
||||
'method' => 'GET',
|
||||
'url' => fn ($row) => route('admin.settings.attributes.edit', $row->id),
|
||||
]);
|
||||
}
|
||||
|
||||
if (bouncer()->hasPermission('settings.automation.attributes.delete')) {
|
||||
$this->addAction([
|
||||
'icon' => 'icon-delete',
|
||||
'title' => trans('admin::app.settings.attributes.index.datagrid.delete'),
|
||||
'method' => 'DELETE',
|
||||
'url' => fn ($row) => route('admin.settings.attributes.delete', $row->id),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare mass actions.
|
||||
*/
|
||||
public function prepareMassActions(): void
|
||||
{
|
||||
$this->addMassAction([
|
||||
'icon' => 'icon-delete',
|
||||
'title' => trans('admin::app.settings.attributes.index.datagrid.delete'),
|
||||
'method' => 'POST',
|
||||
'url' => route('admin.settings.attributes.mass_delete'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Admin\DataGrids\Settings\DataTransfer;
|
||||
|
||||
use Illuminate\Database\Query\Builder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Webkul\DataGrid\DataGrid;
|
||||
|
||||
class ImportDataGrid extends DataGrid
|
||||
{
|
||||
/**
|
||||
* Prepare query builder.
|
||||
*/
|
||||
public function prepareQueryBuilder(): Builder
|
||||
{
|
||||
return DB::table('imports')
|
||||
->select(
|
||||
'id',
|
||||
'state',
|
||||
'file_path',
|
||||
'error_file_path',
|
||||
'started_at',
|
||||
'completed_at',
|
||||
'type',
|
||||
'summary',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare Columns.
|
||||
*/
|
||||
public function prepareColumns(): void
|
||||
{
|
||||
$this->addColumn([
|
||||
'index' => 'id',
|
||||
'label' => trans('admin::app.settings.data-transfer.imports.index.datagrid.id'),
|
||||
'type' => 'integer',
|
||||
'filterable' => true,
|
||||
'sortable' => true,
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'type',
|
||||
'label' => trans('admin::app.settings.data-transfer.imports.index.datagrid.type'),
|
||||
'type' => 'string',
|
||||
'filterable' => true,
|
||||
'sortable' => true,
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'state',
|
||||
'label' => trans('admin::app.settings.data-transfer.imports.index.datagrid.state'),
|
||||
'type' => 'string',
|
||||
'filterable' => true,
|
||||
'sortable' => true,
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'file_path',
|
||||
'label' => trans('admin::app.settings.data-transfer.imports.index.datagrid.uploaded-file'),
|
||||
'type' => 'string',
|
||||
'closure' => function ($row) {
|
||||
return '<a href="'.route('admin.settings.data_transfer.imports.download', $row->id).'" class="cursor-pointer text-blue-600 hover:underline">'.$row->file_path.'<a>';
|
||||
},
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'error_file_path',
|
||||
'label' => trans('admin::app.settings.data-transfer.imports.index.datagrid.error-file'),
|
||||
'type' => 'string',
|
||||
'closure' => function ($row) {
|
||||
if (empty($row->error_file_path)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return '<a href="'.route('admin.settings.data_transfer.imports.download_error_report', $row->id).'" class="cursor-pointer text-blue-600 hover:underline">'.$row->error_file_path.'<a>';
|
||||
},
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'started_at',
|
||||
'label' => trans('admin::app.settings.data-transfer.imports.index.datagrid.started-at'),
|
||||
'type' => 'date',
|
||||
'filterable' => true,
|
||||
'filterable_type' => 'date_range',
|
||||
'sortable' => true,
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'completed_at',
|
||||
'label' => trans('admin::app.settings.data-transfer.imports.index.datagrid.completed-at'),
|
||||
'type' => 'date',
|
||||
'filterable' => true,
|
||||
'filterable_type' => 'date_range',
|
||||
'sortable' => true,
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'summary',
|
||||
'label' => trans('admin::app.settings.data-transfer.imports.index.datagrid.summary'),
|
||||
'type' => 'string',
|
||||
'closure' => function ($row) {
|
||||
if (empty($row->summary)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$summary = json_decode($row->summary, true);
|
||||
|
||||
$stats = [];
|
||||
|
||||
foreach ($summary as $type => $value) {
|
||||
$stats[] = trans('admin::app.settings.data-transfer.imports.index.datagrid.'.$type).': '.$summary[$type];
|
||||
}
|
||||
|
||||
return implode(', ', $stats);
|
||||
},
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare actions.
|
||||
*/
|
||||
public function prepareActions(): void
|
||||
{
|
||||
if (bouncer()->hasPermission('settings.data_transfer.imports.import')) {
|
||||
$this->addAction([
|
||||
'index' => 'import',
|
||||
'icon' => 'icon-import',
|
||||
'title' => trans('admin::app.settings.data-transfer.imports.index.datagrid.import'),
|
||||
'method' => 'GET',
|
||||
'url' => function ($row) {
|
||||
return route('admin.settings.data_transfer.imports.import', $row->id);
|
||||
},
|
||||
]);
|
||||
}
|
||||
|
||||
if (bouncer()->hasPermission('settings.data_transfer.imports.edit')) {
|
||||
$this->addAction([
|
||||
'index' => 'edit',
|
||||
'icon' => 'icon-edit',
|
||||
'title' => trans('admin::app.settings.data-transfer.imports.index.datagrid.edit'),
|
||||
'method' => 'GET',
|
||||
'url' => function ($row) {
|
||||
return route('admin.settings.data_transfer.imports.edit', $row->id);
|
||||
},
|
||||
]);
|
||||
}
|
||||
|
||||
if (bouncer()->hasPermission('settings.data_transfer.imports.delete')) {
|
||||
$this->addAction([
|
||||
'index' => 'delete',
|
||||
'icon' => 'icon-delete',
|
||||
'title' => trans('admin::app.settings.data-transfer.imports.index.datagrid.delete'),
|
||||
'method' => 'DELETE',
|
||||
'url' => function ($row) {
|
||||
return route('admin.settings.data_transfer.imports.delete', $row->id);
|
||||
},
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Admin\DataGrids\Settings;
|
||||
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Webkul\DataGrid\DataGrid;
|
||||
|
||||
class EmailTemplateDataGrid extends DataGrid
|
||||
{
|
||||
/**
|
||||
* Prepare query builder.
|
||||
*/
|
||||
public function prepareQueryBuilder()
|
||||
{
|
||||
$queryBuilder = DB::table('email_templates')
|
||||
->addSelect(
|
||||
'email_templates.id',
|
||||
'email_templates.name',
|
||||
'email_templates.subject',
|
||||
);
|
||||
|
||||
$this->addFilter('id', 'email_templates.id');
|
||||
|
||||
return $queryBuilder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add columns.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function prepareColumns()
|
||||
{
|
||||
$this->addColumn([
|
||||
'index' => 'id',
|
||||
'label' => trans('admin::app.settings.email-template.index.datagrid.id'),
|
||||
'type' => 'string',
|
||||
'sortable' => true,
|
||||
'searchable' => true,
|
||||
'filterable' => true,
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'name',
|
||||
'label' => trans('admin::app.settings.email-template.index.datagrid.name'),
|
||||
'type' => 'string',
|
||||
'sortable' => true,
|
||||
'searchable' => true,
|
||||
'filterable' => true,
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'subject',
|
||||
'label' => trans('admin::app.settings.email-template.index.datagrid.subject'),
|
||||
'type' => 'string',
|
||||
'sortable' => true,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare actions.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function prepareActions()
|
||||
{
|
||||
if (bouncer()->hasPermission('settings.automation.email_templates.edit')) {
|
||||
$this->addAction([
|
||||
'index' => 'delete',
|
||||
'icon' => 'icon-edit',
|
||||
'title' => trans('admin::app.settings.email-template.index.datagrid.edit'),
|
||||
'method' => 'GET',
|
||||
'url' => fn ($row) => route('admin.settings.email_templates.edit', $row->id),
|
||||
]);
|
||||
}
|
||||
|
||||
if (bouncer()->hasPermission('settings.automation.email_templates.delete')) {
|
||||
$this->addAction([
|
||||
'index' => 'delete',
|
||||
'icon' => 'icon-delete',
|
||||
'title' => trans('admin::app.settings.email-template.index.datagrid.delete'),
|
||||
'method' => 'DELETE',
|
||||
'url' => fn ($row) => route('admin.settings.email_templates.delete', $row->id),
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Admin\DataGrids\Settings;
|
||||
|
||||
use Illuminate\Database\Query\Builder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Webkul\DataGrid\DataGrid;
|
||||
|
||||
class GroupDataGrid extends DataGrid
|
||||
{
|
||||
/**
|
||||
* Prepare query builder.
|
||||
*/
|
||||
public function prepareQueryBuilder(): Builder
|
||||
{
|
||||
$queryBuilder = DB::table('groups')
|
||||
->addSelect(
|
||||
'groups.id',
|
||||
'groups.name',
|
||||
'groups.description'
|
||||
);
|
||||
|
||||
$this->addFilter('id', 'groups.id');
|
||||
|
||||
return $queryBuilder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare columns.
|
||||
*/
|
||||
public function prepareColumns(): void
|
||||
{
|
||||
$this->addColumn([
|
||||
'index' => 'id',
|
||||
'label' => trans('admin::app.settings.groups.index.datagrid.id'),
|
||||
'type' => 'string',
|
||||
'searchable' => true,
|
||||
'filterable' => true,
|
||||
'sortable' => true,
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'name',
|
||||
'type' => 'string',
|
||||
'label' => trans('admin::app.settings.groups.index.datagrid.name'),
|
||||
'searchable' => true,
|
||||
'filterable' => true,
|
||||
'sortable' => true,
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'description',
|
||||
'label' => trans('admin::app.settings.groups.index.datagrid.description'),
|
||||
'type' => 'string',
|
||||
'sortable' => false,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare actions.
|
||||
*/
|
||||
public function prepareActions(): void
|
||||
{
|
||||
if (bouncer()->hasPermission('settings.user.groups.edit')) {
|
||||
$this->addAction([
|
||||
'index' => 'edit',
|
||||
'icon' => 'icon-edit',
|
||||
'title' => trans('admin::app.settings.groups.index.datagrid.edit'),
|
||||
'method' => 'GET',
|
||||
'url' => fn ($row) => route('admin.settings.groups.edit', $row->id),
|
||||
]);
|
||||
}
|
||||
|
||||
if (bouncer()->hasPermission('settings.user.groups.delete')) {
|
||||
$this->addAction([
|
||||
'index' => 'delete',
|
||||
'icon' => 'icon-delete',
|
||||
'title' => trans('admin::app.settings.groups.index.datagrid.delete'),
|
||||
'method' => 'DELETE',
|
||||
'url' => fn ($row) => route('admin.settings.groups.delete', $row->id),
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Admin\DataGrids\Settings\Marketing;
|
||||
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Webkul\DataGrid\DataGrid;
|
||||
|
||||
class CampaignDatagrid extends DataGrid
|
||||
{
|
||||
/**
|
||||
* Prepare query builder.
|
||||
*/
|
||||
public function prepareQueryBuilder()
|
||||
{
|
||||
$queryBuilder = DB::table('marketing_campaigns')
|
||||
->addSelect(
|
||||
'marketing_campaigns.id',
|
||||
'marketing_campaigns.name',
|
||||
'marketing_campaigns.subject',
|
||||
'marketing_campaigns.status',
|
||||
);
|
||||
|
||||
$this->addFilter('id', 'marketing_campaigns.id');
|
||||
|
||||
return $queryBuilder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add columns.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function prepareColumns()
|
||||
{
|
||||
$this->addColumn([
|
||||
'index' => 'id',
|
||||
'label' => trans('admin::app.settings.marketing.campaigns.index.datagrid.id'),
|
||||
'type' => 'string',
|
||||
'sortable' => true,
|
||||
'searchable' => true,
|
||||
'filterable' => true,
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'name',
|
||||
'label' => trans('admin::app.settings.marketing.campaigns.index.datagrid.name'),
|
||||
'type' => 'string',
|
||||
'sortable' => true,
|
||||
'searchable' => true,
|
||||
'filterable' => true,
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'subject',
|
||||
'label' => trans('admin::app.settings.marketing.campaigns.index.datagrid.subject'),
|
||||
'type' => 'string',
|
||||
'sortable' => true,
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'status',
|
||||
'label' => trans('admin::app.settings.marketing.campaigns.index.datagrid.status'),
|
||||
'type' => 'string',
|
||||
'sortable' => true,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare actions.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function prepareActions()
|
||||
{
|
||||
if (bouncer()->hasPermission('settings.automation.campaigns.edit')) {
|
||||
$this->addAction([
|
||||
'index' => 'edit',
|
||||
'icon' => 'icon-edit',
|
||||
'title' => trans('admin::app.settings.marketing.campaigns.index.datagrid.edit'),
|
||||
'method' => 'GET',
|
||||
'url' => fn ($row) => route('admin.settings.marketing.campaigns.edit', $row->id),
|
||||
]);
|
||||
}
|
||||
|
||||
if (bouncer()->hasPermission('settings.automation.campaigns.delete')) {
|
||||
$this->addAction([
|
||||
'index' => 'delete',
|
||||
'icon' => 'icon-delete',
|
||||
'title' => trans('admin::app.settings.marketing.campaigns.index.datagrid.delete'),
|
||||
'method' => 'DELETE',
|
||||
'url' => fn ($row) => route('admin.settings.marketing.campaigns.delete', $row->id),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare mass actions.
|
||||
*/
|
||||
public function prepareMassActions(): void
|
||||
{
|
||||
if (bouncer()->hasPermission('settings.automation.campaigns.mass_delete')) {
|
||||
$this->addMassAction([
|
||||
'icon' => 'icon-delete',
|
||||
'title' => trans('admin::app.settings.marketing.campaigns.index.datagrid.delete'),
|
||||
'method' => 'POST',
|
||||
'url' => route('admin.settings.marketing.campaigns.mass_delete'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Admin\DataGrids\Settings\Marketing;
|
||||
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Webkul\DataGrid\DataGrid;
|
||||
|
||||
class EventDataGrid extends DataGrid
|
||||
{
|
||||
/**
|
||||
* Prepare query builder.
|
||||
*/
|
||||
public function prepareQueryBuilder()
|
||||
{
|
||||
$queryBuilder = DB::table('marketing_events')
|
||||
->addSelect(
|
||||
'marketing_events.id',
|
||||
'marketing_events.name',
|
||||
'marketing_events.description',
|
||||
'marketing_events.date',
|
||||
);
|
||||
|
||||
$this->addFilter('id', 'marketing_events.id');
|
||||
|
||||
return $queryBuilder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add columns.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function prepareColumns()
|
||||
{
|
||||
$this->addColumn([
|
||||
'index' => 'id',
|
||||
'label' => trans('admin::app.settings.marketing.events.index.datagrid.id'),
|
||||
'type' => 'string',
|
||||
'sortable' => true,
|
||||
'searchable' => true,
|
||||
'filterable' => true,
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'name',
|
||||
'label' => trans('admin::app.settings.marketing.events.index.datagrid.name'),
|
||||
'type' => 'string',
|
||||
'sortable' => true,
|
||||
'searchable' => true,
|
||||
'filterable' => true,
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'description',
|
||||
'label' => trans('admin::app.settings.marketing.events.index.datagrid.description'),
|
||||
'type' => 'string',
|
||||
'sortable' => true,
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'date',
|
||||
'label' => trans('admin::app.settings.marketing.events.index.datagrid.date'),
|
||||
'type' => 'string',
|
||||
'sortable' => true,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare actions.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function prepareActions()
|
||||
{
|
||||
if (bouncer()->hasPermission('settings.automation.events.edit')) {
|
||||
$this->addAction([
|
||||
'index' => 'edit',
|
||||
'icon' => 'icon-edit',
|
||||
'title' => trans('admin::app.settings.marketing.events.index.datagrid.edit'),
|
||||
'method' => 'GET',
|
||||
'url' => fn ($row) => route('admin.settings.marketing.events.edit', $row->id),
|
||||
]);
|
||||
}
|
||||
|
||||
if (bouncer()->hasPermission('settings.automation.events.delete')) {
|
||||
$this->addAction([
|
||||
'index' => 'delete',
|
||||
'icon' => 'icon-delete',
|
||||
'title' => trans('admin::app.settings.marketing.events.index.datagrid.delete'),
|
||||
'method' => 'DELETE',
|
||||
'url' => fn ($row) => route('admin.settings.marketing.events.delete', $row->id),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare mass actions.
|
||||
*/
|
||||
public function prepareMassActions(): void
|
||||
{
|
||||
if (bouncer()->hasPermission('settings.automation.events.delete')) {
|
||||
$this->addMassAction([
|
||||
'icon' => 'icon-delete',
|
||||
'title' => trans('admin::app.settings.marketing.events.index.datagrid.delete'),
|
||||
'method' => 'POST',
|
||||
'url' => route('admin.settings.marketing.events.mass_delete'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Admin\DataGrids\Settings;
|
||||
|
||||
use Illuminate\Database\Query\Builder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Webkul\DataGrid\DataGrid;
|
||||
|
||||
class PipelineDataGrid extends DataGrid
|
||||
{
|
||||
/**
|
||||
* Prepare query builder.
|
||||
*/
|
||||
public function prepareQueryBuilder(): Builder
|
||||
{
|
||||
$queryBuilder = DB::table('lead_pipelines')
|
||||
->addSelect(
|
||||
'lead_pipelines.id',
|
||||
'lead_pipelines.name',
|
||||
'lead_pipelines.rotten_days',
|
||||
'lead_pipelines.is_default',
|
||||
);
|
||||
|
||||
$this->addFilter('id', 'lead_pipelines.id');
|
||||
|
||||
return $queryBuilder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare columns.
|
||||
*/
|
||||
public function prepareColumns(): void
|
||||
{
|
||||
$this->addColumn([
|
||||
'index' => 'id',
|
||||
'label' => trans('admin::app.settings.pipelines.index.datagrid.id'),
|
||||
'type' => 'string',
|
||||
'sortable' => true,
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'name',
|
||||
'label' => trans('admin::app.settings.pipelines.index.datagrid.name'),
|
||||
'type' => 'string',
|
||||
'searchable' => true,
|
||||
'filterable' => true,
|
||||
'sortable' => true,
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'rotten_days',
|
||||
'label' => trans('admin::app.settings.pipelines.index.datagrid.rotten-days'),
|
||||
'type' => 'string',
|
||||
'sortable' => true,
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'is_default',
|
||||
'label' => trans('admin::app.settings.pipelines.index.datagrid.is-default'),
|
||||
'type' => 'boolean',
|
||||
'searchable' => true,
|
||||
'filterable' => true,
|
||||
'sortable' => true,
|
||||
'closure' => fn ($value) => trans('admin::app.settings.pipelines.index.datagrid.'.($value->is_default ? 'yes' : 'no')),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare actions.
|
||||
*/
|
||||
public function prepareActions(): void
|
||||
{
|
||||
if (bouncer()->hasPermission('settings.lead.pipelines.edit')) {
|
||||
$this->addAction([
|
||||
'index' => 'edit',
|
||||
'icon' => 'icon-edit',
|
||||
'title' => trans('admin::app.settings.pipelines.index.datagrid.edit'),
|
||||
'method' => 'GET',
|
||||
'url' => fn ($row) => route('admin.settings.pipelines.edit', $row->id),
|
||||
]);
|
||||
}
|
||||
|
||||
if (bouncer()->hasPermission('settings.lead.pipelines.delete')) {
|
||||
$this->addAction([
|
||||
'index' => 'delete',
|
||||
'icon' => 'icon-delete',
|
||||
'title' => trans('admin::app.settings.pipelines.index.datagrid.delete'),
|
||||
'method' => 'DELETE',
|
||||
'url' => fn ($row) => route('admin.settings.pipelines.delete', $row->id),
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
102
packages/Webkul/Admin/src/DataGrids/Settings/RoleDataGrid.php
Normal file
102
packages/Webkul/Admin/src/DataGrids/Settings/RoleDataGrid.php
Normal file
@@ -0,0 +1,102 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Admin\DataGrids\Settings;
|
||||
|
||||
use Illuminate\Database\Query\Builder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Webkul\DataGrid\DataGrid;
|
||||
|
||||
class RoleDataGrid extends DataGrid
|
||||
{
|
||||
/**
|
||||
* Prepare query builder.
|
||||
*/
|
||||
public function prepareQueryBuilder(): Builder
|
||||
{
|
||||
$queryBuilder = DB::table('roles')
|
||||
->addSelect(
|
||||
'roles.id',
|
||||
'roles.name',
|
||||
'roles.description',
|
||||
'roles.permission_type'
|
||||
);
|
||||
|
||||
$this->addFilter('id', 'roles.id');
|
||||
$this->addFilter('name', 'roles.name');
|
||||
|
||||
return $queryBuilder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare Columns.
|
||||
*/
|
||||
public function prepareColumns(): void
|
||||
{
|
||||
$this->addColumn([
|
||||
'index' => 'id',
|
||||
'label' => trans('admin::app.settings.roles.index.datagrid.id'),
|
||||
'type' => 'string',
|
||||
'filterable' => true,
|
||||
'sortable' => true,
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'name',
|
||||
'label' => trans('admin::app.settings.roles.index.datagrid.name'),
|
||||
'type' => 'string',
|
||||
'filterable' => true,
|
||||
'sortable' => true,
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'description',
|
||||
'label' => trans('admin::app.settings.roles.index.datagrid.description'),
|
||||
'type' => 'string',
|
||||
'sortable' => false,
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'permission_type',
|
||||
'label' => trans('admin::app.settings.roles.index.datagrid.permission-type'),
|
||||
'type' => 'string',
|
||||
'searchable' => true,
|
||||
'filterable' => true,
|
||||
'filterable_type' => 'dropdown',
|
||||
'filterable_options' => [
|
||||
[
|
||||
'label' => trans('admin::app.settings.roles.index.datagrid.custom'),
|
||||
'value' => 'custom',
|
||||
],
|
||||
[
|
||||
'label' => trans('admin::app.settings.roles.index.datagrid.all'),
|
||||
'value' => 'all',
|
||||
],
|
||||
],
|
||||
'sortable' => true,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare actions.
|
||||
*/
|
||||
public function prepareActions(): void
|
||||
{
|
||||
if (bouncer()->hasPermission('settings.user.roles.edit')) {
|
||||
$this->addAction([
|
||||
'icon' => 'icon-edit',
|
||||
'title' => trans('admin::app.settings.roles.index.datagrid.edit'),
|
||||
'method' => 'GET',
|
||||
'url' => fn ($row) => route('admin.settings.roles.edit', $row->id),
|
||||
]);
|
||||
}
|
||||
|
||||
if (bouncer()->hasPermission('settings.user.roles.delete')) {
|
||||
$this->addAction([
|
||||
'icon' => 'icon-delete',
|
||||
'title' => trans('admin::app.settings.roles.index.datagrid.delete'),
|
||||
'method' => 'DELETE',
|
||||
'url' => fn ($row) => route('admin.settings.roles.delete', $row->id),
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Admin\DataGrids\Settings;
|
||||
|
||||
use Illuminate\Database\Query\Builder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Webkul\DataGrid\DataGrid;
|
||||
|
||||
class SourceDataGrid extends DataGrid
|
||||
{
|
||||
/**
|
||||
* Prepare query builder.
|
||||
*/
|
||||
public function prepareQueryBuilder(): Builder
|
||||
{
|
||||
$queryBuilder = DB::table('lead_sources')
|
||||
->addSelect(
|
||||
'lead_sources.id',
|
||||
'lead_sources.name'
|
||||
);
|
||||
|
||||
$this->addFilter('id', 'lead_sources.id');
|
||||
|
||||
return $queryBuilder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare Columns.
|
||||
*/
|
||||
public function prepareColumns(): void
|
||||
{
|
||||
$this->addColumn([
|
||||
'index' => 'id',
|
||||
'label' => trans('admin::app.settings.sources.index.datagrid.id'),
|
||||
'type' => 'string',
|
||||
'sortable' => true,
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'name',
|
||||
'label' => trans('admin::app.settings.sources.index.datagrid.name'),
|
||||
'type' => 'string',
|
||||
'searchable' => true,
|
||||
'filterable' => true,
|
||||
'sortable' => true,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare actions.
|
||||
*/
|
||||
public function prepareActions(): void
|
||||
{
|
||||
if (bouncer()->hasPermission('settings.lead.sources.edit')) {
|
||||
$this->addAction([
|
||||
'index' => 'edit',
|
||||
'icon' => 'icon-edit',
|
||||
'title' => trans('admin::app.settings.sources.index.datagrid.edit'),
|
||||
'method' => 'GET',
|
||||
'url' => fn ($row) => route('admin.settings.sources.edit', $row->id),
|
||||
]);
|
||||
}
|
||||
|
||||
if (bouncer()->hasPermission('settings.lead.sources.delete')) {
|
||||
$this->addAction([
|
||||
'index' => 'delete',
|
||||
'icon' => 'icon-delete',
|
||||
'title' => trans('admin::app.settings.sources.index.datagrid.delete'),
|
||||
'method' => 'DELETE',
|
||||
'url' => fn ($row) => route('admin.settings.sources.delete', $row->id),
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
124
packages/Webkul/Admin/src/DataGrids/Settings/TagDataGrid.php
Normal file
124
packages/Webkul/Admin/src/DataGrids/Settings/TagDataGrid.php
Normal file
@@ -0,0 +1,124 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Admin\DataGrids\Settings;
|
||||
|
||||
use Illuminate\Database\Query\Builder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Webkul\DataGrid\DataGrid;
|
||||
|
||||
class TagDataGrid extends DataGrid
|
||||
{
|
||||
/**
|
||||
* Prepare query builder.
|
||||
*/
|
||||
public function prepareQueryBuilder(): Builder
|
||||
{
|
||||
$queryBuilder = DB::table('tags')
|
||||
->addSelect(
|
||||
'tags.id',
|
||||
'tags.name',
|
||||
'tags.color',
|
||||
'tags.created_at',
|
||||
'users.name as user_name',
|
||||
)
|
||||
->leftJoin('users', 'tags.user_id', '=', 'users.id');
|
||||
|
||||
if ($userIds = bouncer()->getAuthorizedUserIds()) {
|
||||
$queryBuilder->whereIn('tags.user_id', $userIds);
|
||||
}
|
||||
|
||||
$this->addFilter('id', 'tags.id');
|
||||
$this->addFilter('name', 'tags.name');
|
||||
$this->addFilter('created_at', 'tags.created_at');
|
||||
$this->addFilter('user_name', 'users.id');
|
||||
|
||||
return $queryBuilder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare Columns.
|
||||
*/
|
||||
public function prepareColumns(): void
|
||||
{
|
||||
$this->addColumn([
|
||||
'index' => 'id',
|
||||
'label' => trans('admin::app.settings.tags.index.datagrid.id'),
|
||||
'type' => 'string',
|
||||
'searchable' => true,
|
||||
'sortable' => true,
|
||||
'filterable' => true,
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'name',
|
||||
'label' => trans('admin::app.settings.tags.index.datagrid.name'),
|
||||
'type' => 'string',
|
||||
'searchable' => true,
|
||||
'sortable' => true,
|
||||
'filterable' => true,
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'user_name',
|
||||
'label' => trans('admin::app.settings.tags.index.datagrid.users'),
|
||||
'type' => 'string',
|
||||
'searchable' => true,
|
||||
'sortable' => true,
|
||||
'filterable' => true,
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'created_at',
|
||||
'label' => trans('admin::app.settings.tags.index.datagrid.created-at'),
|
||||
'type' => 'date',
|
||||
'searchable' => true,
|
||||
'filterable' => true,
|
||||
'sortable' => true,
|
||||
'filterable_type' => 'date_range',
|
||||
'closure' => fn ($row) => core()->formatDate($row->created_at),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare actions.
|
||||
*/
|
||||
public function prepareActions(): void
|
||||
{
|
||||
if (bouncer()->hasPermission('settings.other_settings.tags.edit')) {
|
||||
$this->addAction([
|
||||
'index' => 'edit',
|
||||
'icon' => 'icon-edit',
|
||||
'title' => trans('admin::app.settings.tags.index.datagrid.edit'),
|
||||
'method' => 'GET',
|
||||
'url' => function ($row) {
|
||||
return route('admin.settings.tags.edit', $row->id);
|
||||
},
|
||||
]);
|
||||
}
|
||||
|
||||
if (bouncer()->hasPermission('settings.other_settings.tags.delete')) {
|
||||
$this->addAction([
|
||||
'index' => 'delete',
|
||||
'icon' => 'icon-delete',
|
||||
'title' => trans('admin::app.settings.tags.index.datagrid.delete'),
|
||||
'method' => 'DELETE',
|
||||
'url' => function ($row) {
|
||||
return route('admin.settings.tags.delete', $row->id);
|
||||
},
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare mass actions.
|
||||
*/
|
||||
public function prepareMassActions(): void
|
||||
{
|
||||
$this->addMassAction([
|
||||
'icon' => 'icon-delete',
|
||||
'title' => trans('admin::app.settings.tags.index.datagrid.delete'),
|
||||
'method' => 'POST',
|
||||
'url' => route('admin.settings.tags.mass_delete'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Admin\DataGrids\Settings;
|
||||
|
||||
use Illuminate\Database\Query\Builder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Webkul\DataGrid\DataGrid;
|
||||
|
||||
class TypeDataGrid extends DataGrid
|
||||
{
|
||||
/**
|
||||
* Prepare query builder.
|
||||
*/
|
||||
public function prepareQueryBuilder(): Builder
|
||||
{
|
||||
$queryBuilder = DB::table('lead_types')
|
||||
->addSelect(
|
||||
'lead_types.id',
|
||||
'lead_types.name'
|
||||
);
|
||||
|
||||
$this->addFilter('id', 'lead_types.id');
|
||||
|
||||
return $queryBuilder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare Columns.
|
||||
*/
|
||||
public function prepareColumns(): void
|
||||
{
|
||||
$this->addColumn([
|
||||
'index' => 'id',
|
||||
'label' => trans('admin::app.settings.types.index.datagrid.id'),
|
||||
'type' => 'string',
|
||||
'filterable' => true,
|
||||
'sortable' => true,
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'name',
|
||||
'label' => trans('admin::app.settings.types.index.datagrid.name'),
|
||||
'type' => 'string',
|
||||
'filterable' => true,
|
||||
'sortable' => true,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare Actions.
|
||||
*/
|
||||
public function prepareActions(): void
|
||||
{
|
||||
if (bouncer()->hasPermission('settings.lead.types.edit')) {
|
||||
$this->addAction([
|
||||
'index' => 'edit',
|
||||
'icon' => 'icon-edit',
|
||||
'title' => trans('admin::app.settings.roles.index.datagrid.edit'),
|
||||
'method' => 'GET',
|
||||
'url' => fn ($row) => route('admin.settings.types.update', $row->id),
|
||||
]);
|
||||
}
|
||||
|
||||
if (bouncer()->hasPermission('settings.lead.types.delete')) {
|
||||
$this->addAction([
|
||||
'index' => 'delete',
|
||||
'icon' => 'icon-delete',
|
||||
'title' => trans('admin::app.settings.roles.index.datagrid.delete'),
|
||||
'method' => 'DELETE',
|
||||
'url' => fn ($row) => route('admin.settings.types.delete', $row->id),
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
146
packages/Webkul/Admin/src/DataGrids/Settings/UserDataGrid.php
Normal file
146
packages/Webkul/Admin/src/DataGrids/Settings/UserDataGrid.php
Normal file
@@ -0,0 +1,146 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Admin\DataGrids\Settings;
|
||||
|
||||
use Illuminate\Database\Query\Builder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Webkul\DataGrid\DataGrid;
|
||||
|
||||
class UserDataGrid extends DataGrid
|
||||
{
|
||||
/**
|
||||
* Prepare query builder.
|
||||
*/
|
||||
public function prepareQueryBuilder(): Builder
|
||||
{
|
||||
$queryBuilder = DB::table('users')
|
||||
->distinct()
|
||||
->addSelect(
|
||||
'id',
|
||||
'name',
|
||||
'email',
|
||||
'image',
|
||||
'status',
|
||||
'created_at'
|
||||
)
|
||||
->leftJoin('user_groups', 'id', '=', 'user_groups.user_id');
|
||||
|
||||
if ($userIds = bouncer()->getAuthorizedUserIds()) {
|
||||
$queryBuilder->whereIn('id', $userIds);
|
||||
}
|
||||
|
||||
return $queryBuilder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add columns.
|
||||
*/
|
||||
public function prepareColumns(): void
|
||||
{
|
||||
$this->addColumn([
|
||||
'index' => 'id',
|
||||
'label' => trans('admin::app.settings.users.index.datagrid.id'),
|
||||
'type' => 'string',
|
||||
'sortable' => true,
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'name',
|
||||
'label' => trans('admin::app.settings.users.index.datagrid.name'),
|
||||
'type' => 'string',
|
||||
'sortable' => true,
|
||||
'searchable' => true,
|
||||
'filterable' => true,
|
||||
'closure' => function ($row) {
|
||||
return [
|
||||
'image' => $row->image ? Storage::url($row->image) : null,
|
||||
'name' => $row->name,
|
||||
];
|
||||
},
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'email',
|
||||
'label' => trans('admin::app.settings.users.index.datagrid.email'),
|
||||
'type' => 'string',
|
||||
'sortable' => true,
|
||||
'searchable' => true,
|
||||
'filterable' => true,
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'status',
|
||||
'label' => trans('admin::app.settings.users.index.datagrid.status'),
|
||||
'type' => 'boolean',
|
||||
'filterable' => true,
|
||||
'sortable' => true,
|
||||
'searchable' => true,
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'created_at',
|
||||
'label' => trans('admin::app.settings.users.index.datagrid.created-at'),
|
||||
'type' => 'date',
|
||||
'sortable' => true,
|
||||
'searchable' => true,
|
||||
'filterable_type' => 'date_range',
|
||||
'filterable' => true,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare actions.
|
||||
*/
|
||||
public function prepareActions(): void
|
||||
{
|
||||
if (bouncer()->hasPermission('settings.user.users.edit')) {
|
||||
$this->addAction([
|
||||
'index' => 'edit',
|
||||
'icon' => 'icon-edit',
|
||||
'title' => trans('admin::app.settings.users.index.datagrid.edit'),
|
||||
'method' => 'GET',
|
||||
'url' => fn ($row) => route('admin.settings.users.edit', $row->id),
|
||||
]);
|
||||
}
|
||||
|
||||
if (bouncer()->hasPermission('settings.user.users.delete')) {
|
||||
$this->addAction([
|
||||
'index' => 'delete',
|
||||
'icon' => 'icon-delete',
|
||||
'title' => trans('admin::app.settings.users.index.datagrid.delete'),
|
||||
'method' => 'DELETE',
|
||||
'url' => fn ($row) => route('admin.settings.users.delete', $row->id),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare mass actions.
|
||||
*/
|
||||
public function prepareMassActions(): void
|
||||
{
|
||||
$this->addMassAction([
|
||||
'icon' => 'icon-delete',
|
||||
'title' => trans('admin::app.settings.users.index.datagrid.delete'),
|
||||
'method' => 'POST',
|
||||
'url' => route('admin.settings.users.mass_delete'),
|
||||
]);
|
||||
|
||||
$this->addMassAction([
|
||||
'title' => trans('admin::app.settings.users.index.datagrid.update-status'),
|
||||
'method' => 'POST',
|
||||
'url' => route('admin.settings.users.mass_update'),
|
||||
'options' => [
|
||||
[
|
||||
'label' => trans('admin::app.settings.users.index.datagrid.active'),
|
||||
'value' => 1,
|
||||
],
|
||||
[
|
||||
'label' => trans('admin::app.settings.users.index.datagrid.inactive'),
|
||||
'value' => 0,
|
||||
],
|
||||
],
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Admin\DataGrids\Settings;
|
||||
|
||||
use Illuminate\Database\Query\Builder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Webkul\DataGrid\DataGrid;
|
||||
|
||||
class WarehouseDataGrid extends DataGrid
|
||||
{
|
||||
/**
|
||||
* Prepare query builder.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function prepareQueryBuilder(): Builder
|
||||
{
|
||||
$queryBuilder = DB::table('warehouses')
|
||||
->leftJoin('product_inventories', 'warehouses.id', '=', 'product_inventories.warehouse_id')
|
||||
->select(
|
||||
'warehouses.id',
|
||||
'warehouses.name',
|
||||
'warehouses.contact_name',
|
||||
'warehouses.contact_emails',
|
||||
'warehouses.contact_numbers',
|
||||
'warehouses.created_at',
|
||||
)
|
||||
->addSelect(DB::raw('count(DISTINCT '.DB::getTablePrefix().'product_inventories.product_id) as products'))
|
||||
->groupBy('warehouses.id');
|
||||
|
||||
$this->addFilter('id', 'warehouses.id');
|
||||
$this->addFilter('created_at', 'warehouses.created_at');
|
||||
|
||||
return $queryBuilder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add columns.
|
||||
*/
|
||||
public function prepareColumns(): void
|
||||
{
|
||||
$this->addColumn([
|
||||
'index' => 'id',
|
||||
'label' => trans('admin::app.settings.warehouses.index.datagrid.id'),
|
||||
'type' => 'string',
|
||||
'sortable' => true,
|
||||
'filterable' => true,
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'name',
|
||||
'label' => trans('admin::app.settings.warehouses.index.datagrid.name'),
|
||||
'type' => 'string',
|
||||
'sortable' => true,
|
||||
'filterable' => true,
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'contact_name',
|
||||
'label' => trans('admin::app.settings.warehouses.index.datagrid.contact-name'),
|
||||
'type' => 'string',
|
||||
'searchable' => true,
|
||||
'filterable' => true,
|
||||
'sortable' => true,
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'contact_emails',
|
||||
'label' => trans('admin::app.settings.warehouses.index.datagrid.contact-emails'),
|
||||
'type' => 'string',
|
||||
'searchable' => true,
|
||||
'filterable' => true,
|
||||
'sortable' => true,
|
||||
'closure' => function ($row) {
|
||||
$emails = json_decode($row->contact_emails, true);
|
||||
|
||||
if ($emails) {
|
||||
return collect($emails)->pluck('value')->join(', ');
|
||||
}
|
||||
},
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'contact_numbers',
|
||||
'label' => trans('admin::app.settings.warehouses.index.datagrid.contact-numbers'),
|
||||
'type' => 'string',
|
||||
'sortable' => false,
|
||||
'closure' => function ($row) {
|
||||
$numbers = json_decode($row->contact_numbers, true);
|
||||
|
||||
if ($numbers) {
|
||||
return collect($numbers)->pluck('value')->join(', ');
|
||||
}
|
||||
},
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'products',
|
||||
'label' => trans('admin::app.settings.warehouses.index.datagrid.products'),
|
||||
'type' => 'string',
|
||||
'sortable' => true,
|
||||
'filterable' => false,
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'created_at',
|
||||
'label' => trans('admin::app.settings.warehouses.index.datagrid.created-at'),
|
||||
'type' => 'date',
|
||||
'searchable' => true,
|
||||
'filterable' => true,
|
||||
'filterable_type' => 'date_range',
|
||||
'sortable' => true,
|
||||
'closure' => function ($row) {
|
||||
return core()->formatDate($row->created_at);
|
||||
},
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare actions.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function prepareActions()
|
||||
{
|
||||
$this->addAction([
|
||||
'icon' => 'icon-eye',
|
||||
'title' => trans('admin::app.settings.warehouses.index.datagrid.view'),
|
||||
'method' => 'GET',
|
||||
'url' => function ($row) {
|
||||
return route('admin.settings.warehouses.view', $row->id);
|
||||
},
|
||||
]);
|
||||
|
||||
$this->addAction([
|
||||
'icon' => 'icon-edit',
|
||||
'title' => trans('admin::app.settings.warehouses.index.datagrid.edit'),
|
||||
'method' => 'GET',
|
||||
'url' => function ($row) {
|
||||
return route('admin.settings.warehouses.edit', $row->id);
|
||||
},
|
||||
]);
|
||||
|
||||
$this->addAction([
|
||||
'icon' => 'icon-delete',
|
||||
'title' => trans('admin::app.settings.warehouses.index.datagrid.delete'),
|
||||
'method' => 'DELETE',
|
||||
'url' => function ($row) {
|
||||
return route('admin.settings.warehouses.delete', $row->id);
|
||||
},
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Admin\DataGrids\Settings;
|
||||
|
||||
use Illuminate\Database\Query\Builder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Webkul\DataGrid\DataGrid;
|
||||
|
||||
class WebhookDataGrid extends DataGrid
|
||||
{
|
||||
/**
|
||||
* Prepare query builder.
|
||||
*/
|
||||
public function prepareQueryBuilder(): Builder
|
||||
{
|
||||
$queryBuilder = DB::table('webhooks')
|
||||
->addSelect(
|
||||
'webhooks.id',
|
||||
'webhooks.name',
|
||||
'webhooks.entity_type',
|
||||
'webhooks.end_point',
|
||||
);
|
||||
|
||||
$this->addFilter('id', 'webhooks.id');
|
||||
|
||||
return $queryBuilder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare Columns.
|
||||
*/
|
||||
public function prepareColumns(): void
|
||||
{
|
||||
$this->addColumn([
|
||||
'index' => 'id',
|
||||
'label' => trans('admin::app.settings.webhooks.index.datagrid.id'),
|
||||
'type' => 'string',
|
||||
'searchable' => true,
|
||||
'filterable' => true,
|
||||
'sortable' => true,
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'name',
|
||||
'label' => trans('admin::app.settings.webhooks.index.datagrid.name'),
|
||||
'type' => 'string',
|
||||
'searchable' => true,
|
||||
'filterable' => true,
|
||||
'sortable' => true,
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'entity_type',
|
||||
'label' => trans('admin::app.settings.webhooks.index.datagrid.entity-type'),
|
||||
'type' => 'string',
|
||||
'searchable' => true,
|
||||
'filterable' => true,
|
||||
'sortable' => true,
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'end_point',
|
||||
'label' => trans('admin::app.settings.webhooks.index.datagrid.end-point'),
|
||||
'type' => 'string',
|
||||
'searchable' => true,
|
||||
'filterable' => true,
|
||||
'sortable' => true,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare actions.
|
||||
*/
|
||||
public function prepareActions(): void
|
||||
{
|
||||
if (bouncer()->hasPermission('settings.automation.webhooks.edit')) {
|
||||
$this->addAction([
|
||||
'index' => 'edit',
|
||||
'icon' => 'icon-edit',
|
||||
'title' => trans('admin::app.settings.webhooks.index.datagrid.edit'),
|
||||
'method' => 'GET',
|
||||
'url' => fn ($row) => route('admin.settings.webhooks.edit', $row->id),
|
||||
]);
|
||||
}
|
||||
|
||||
if (bouncer()->hasPermission('settings.automation.webhooks.delete')) {
|
||||
$this->addAction([
|
||||
'index' => 'delete',
|
||||
'icon' => 'icon-delete',
|
||||
'title' => trans('admin::app.settings.webhooks.index.datagrid.delete'),
|
||||
'method' => 'DELETE',
|
||||
'url' => fn ($row) => route('admin.settings.webhooks.delete', $row->id),
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Admin\DataGrids\Settings;
|
||||
|
||||
use Illuminate\Database\Query\Builder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Webkul\DataGrid\DataGrid;
|
||||
|
||||
class WorkflowDataGrid extends DataGrid
|
||||
{
|
||||
/**
|
||||
* Prepare query builder.
|
||||
*/
|
||||
public function prepareQueryBuilder(): Builder
|
||||
{
|
||||
$queryBuilder = DB::table('workflows')
|
||||
->addSelect(
|
||||
'workflows.id',
|
||||
'workflows.name'
|
||||
);
|
||||
|
||||
$this->addFilter('id', 'workflows.id');
|
||||
|
||||
return $queryBuilder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare Columns.
|
||||
*/
|
||||
public function prepareColumns(): void
|
||||
{
|
||||
$this->addColumn([
|
||||
'index' => 'id',
|
||||
'label' => trans('admin::app.settings.workflows.index.datagrid.id'),
|
||||
'type' => 'string',
|
||||
'searchable' => true,
|
||||
'filterable' => true,
|
||||
'sortable' => true,
|
||||
]);
|
||||
|
||||
$this->addColumn([
|
||||
'index' => 'name',
|
||||
'label' => trans('admin::app.settings.workflows.index.datagrid.name'),
|
||||
'type' => 'string',
|
||||
'searchable' => true,
|
||||
'filterable' => true,
|
||||
'sortable' => true,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare actions.
|
||||
*/
|
||||
public function prepareActions(): void
|
||||
{
|
||||
if (bouncer()->hasPermission('settings.automation.workflows.edit')) {
|
||||
$this->addAction([
|
||||
'index' => 'edit',
|
||||
'icon' => 'icon-edit',
|
||||
'title' => trans('admin::app.settings.workflows.index.datagrid.edit'),
|
||||
'method' => 'GET',
|
||||
'url' => fn ($row) => route('admin.settings.workflows.edit', $row->id),
|
||||
]);
|
||||
}
|
||||
|
||||
if (bouncer()->hasPermission('settings.automation.workflows.delete')) {
|
||||
$this->addAction([
|
||||
'index' => 'delete',
|
||||
'icon' => 'icon-delete',
|
||||
'title' => trans('admin::app.settings.workflows.index.datagrid.delete'),
|
||||
'method' => 'DELETE',
|
||||
'url' => fn ($row) => route('admin.settings.workflows.delete', $row->id),
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('users', function (Blueprint $table) {
|
||||
$table->string('view_permission')->after('status')->default('global')->nullable();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('users', function (Blueprint $table) {
|
||||
$table->dropColumn('view_permission');
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
DB::table('attributes')->insert([
|
||||
[
|
||||
'id' => '7',
|
||||
'code' => 'expected_close_date',
|
||||
'name' => 'Expected Close Date',
|
||||
'type' => 'date',
|
||||
'entity_type' => 'leads',
|
||||
'lookup_type' => null,
|
||||
'validation' => null,
|
||||
'sort_order' => '8',
|
||||
'is_required' => '0',
|
||||
'is_unique' => '0',
|
||||
'quick_add' => '1',
|
||||
'is_user_defined' => '0',
|
||||
'created_at' => Carbon::now(),
|
||||
'updated_at' => Carbon::now(),
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down() {}
|
||||
};
|
||||
117
packages/Webkul/Admin/src/Exceptions/Handler.php
Executable file
117
packages/Webkul/Admin/src/Exceptions/Handler.php
Executable file
@@ -0,0 +1,117 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Admin\Exceptions;
|
||||
|
||||
use App\Exceptions\Handler as AppExceptionHandler;
|
||||
use Illuminate\Auth\AuthenticationException;
|
||||
use Illuminate\Container\Container;
|
||||
use Illuminate\Database\Eloquent\ModelNotFoundException;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use PDOException;
|
||||
use Symfony\Component\HttpKernel\Exception\HttpException;
|
||||
use Throwable;
|
||||
|
||||
class Handler extends AppExceptionHandler
|
||||
{
|
||||
/**
|
||||
* Json error messages.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $jsonErrorMessages = [];
|
||||
|
||||
/**
|
||||
* Create handler instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(Container $container)
|
||||
{
|
||||
parent::__construct($container);
|
||||
|
||||
$this->jsonErrorMessages = [
|
||||
'404' => trans('admin::app.common.resource-not-found'),
|
||||
'403' => trans('admin::app.common.forbidden-error'),
|
||||
'401' => trans('admin::app.common.unauthenticated'),
|
||||
'500' => trans('admin::app.common.internal-server-error'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Render an exception into an HTTP response.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function render($request, Throwable $exception)
|
||||
{
|
||||
if (! config('app.debug')) {
|
||||
return $this->renderCustomResponse($exception);
|
||||
}
|
||||
|
||||
return parent::render($request, $exception);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert an authentication exception into a response.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
protected function unauthenticated($request, AuthenticationException $exception)
|
||||
{
|
||||
if ($request->expectsJson()) {
|
||||
return response()->json(['message' => $this->jsonErrorMessages[401]], 401);
|
||||
}
|
||||
|
||||
return redirect()->guest(route('customer.session.index'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Render custom HTTP response.
|
||||
*
|
||||
* @return \Illuminate\Http\Response|null
|
||||
*/
|
||||
private function renderCustomResponse(Throwable $exception)
|
||||
{
|
||||
if ($exception instanceof HttpException) {
|
||||
$statusCode = in_array($exception->getStatusCode(), [401, 403, 404, 503])
|
||||
? $exception->getStatusCode()
|
||||
: 500;
|
||||
|
||||
return $this->response($statusCode);
|
||||
}
|
||||
|
||||
if ($exception instanceof ValidationException) {
|
||||
return parent::render(request(), $exception);
|
||||
}
|
||||
|
||||
if ($exception instanceof ModelNotFoundException) {
|
||||
return $this->response(404);
|
||||
} elseif ($exception instanceof PDOException || $exception instanceof \ParseError) {
|
||||
return $this->response(500);
|
||||
} else {
|
||||
return $this->response(500);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return custom response.
|
||||
*
|
||||
* @param string $path
|
||||
* @param string $errorCode
|
||||
* @return mixed
|
||||
*/
|
||||
private function response($errorCode)
|
||||
{
|
||||
if (request()->expectsJson()) {
|
||||
return response()->json([
|
||||
'message' => isset($this->jsonErrorMessages[$errorCode])
|
||||
? $this->jsonErrorMessages[$errorCode]
|
||||
: trans('admin::app.common.something-went-wrong'),
|
||||
], $errorCode);
|
||||
}
|
||||
|
||||
return response()->view('admin::errors.index', compact('errorCode'));
|
||||
}
|
||||
}
|
||||
18
packages/Webkul/Admin/src/Facades/Bouncer.php
Executable file
18
packages/Webkul/Admin/src/Facades/Bouncer.php
Executable file
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Admin\Facades;
|
||||
|
||||
use Illuminate\Support\Facades\Facade;
|
||||
|
||||
class Bouncer extends Facade
|
||||
{
|
||||
/**
|
||||
* Get the registered name of the component.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected static function getFacadeAccessor()
|
||||
{
|
||||
return 'bouncer';
|
||||
}
|
||||
}
|
||||
142
packages/Webkul/Admin/src/Helpers/Dashboard.php
Normal file
142
packages/Webkul/Admin/src/Helpers/Dashboard.php
Normal file
@@ -0,0 +1,142 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Admin\Helpers;
|
||||
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Collection;
|
||||
use Webkul\Admin\Helpers\Reporting\Activity;
|
||||
use Webkul\Admin\Helpers\Reporting\Lead;
|
||||
use Webkul\Admin\Helpers\Reporting\Organization;
|
||||
use Webkul\Admin\Helpers\Reporting\Person;
|
||||
use Webkul\Admin\Helpers\Reporting\Product;
|
||||
use Webkul\Admin\Helpers\Reporting\Quote;
|
||||
|
||||
class Dashboard
|
||||
{
|
||||
/**
|
||||
* Create a controller instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(
|
||||
protected Lead $leadReporting,
|
||||
protected Activity $activityReporting,
|
||||
protected Product $productReporting,
|
||||
protected Person $personReporting,
|
||||
protected Organization $organizationReporting,
|
||||
protected Quote $quoteReporting,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Returns the overall revenue statistics.
|
||||
*/
|
||||
public function getRevenueStats(): array
|
||||
{
|
||||
return [
|
||||
'total_won_revenue' => $this->leadReporting->getTotalWonLeadValueProgress(),
|
||||
'total_lost_revenue' => $this->leadReporting->getTotalLostLeadValueProgress(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the overall statistics.
|
||||
*/
|
||||
public function getOverAllStats(): array
|
||||
{
|
||||
return [
|
||||
'total_leads' => $this->leadReporting->getTotalLeadsProgress(),
|
||||
'average_lead_value' => $this->leadReporting->getAverageLeadValueProgress(),
|
||||
'average_leads_per_day' => $this->leadReporting->getAverageLeadsPerDayProgress(),
|
||||
'total_quotations' => $this->quoteReporting->getTotalQuotesProgress(),
|
||||
'total_persons' => $this->personReporting->getTotalPersonsProgress(),
|
||||
'total_organizations' => $this->organizationReporting->getTotalOrganizationsProgress(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns leads statistics.
|
||||
*/
|
||||
public function getTotalLeadsStats(): array
|
||||
{
|
||||
return [
|
||||
'all' => [
|
||||
'over_time' => $this->leadReporting->getTotalLeadsOverTime(),
|
||||
],
|
||||
|
||||
'won' => [
|
||||
'over_time' => $this->leadReporting->getTotalWonLeadsOverTime(),
|
||||
],
|
||||
'lost' => [
|
||||
'over_time' => $this->leadReporting->getTotalLostLeadsOverTime(),
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns leads revenue statistics by sources.
|
||||
*/
|
||||
public function getLeadsStatsBySources(): mixed
|
||||
{
|
||||
return $this->leadReporting->getTotalWonLeadValueBySources();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns leads revenue statistics by types.
|
||||
*/
|
||||
public function getLeadsStatsByTypes(): mixed
|
||||
{
|
||||
return $this->leadReporting->getTotalWonLeadValueByTypes();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns open leads statistics by states.
|
||||
*/
|
||||
public function getOpenLeadsByStates(): mixed
|
||||
{
|
||||
return $this->leadReporting->getOpenLeadsByStates();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns top selling products statistics.
|
||||
*/
|
||||
public function getTopSellingProducts(): Collection
|
||||
{
|
||||
return $this->productReporting->getTopSellingProductsByRevenue(5);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns top selling products statistics.
|
||||
*/
|
||||
public function getTopPersons(): Collection
|
||||
{
|
||||
return $this->personReporting->getTopCustomersByRevenue(5);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the start date.
|
||||
*
|
||||
* @return \Carbon\Carbon
|
||||
*/
|
||||
public function getStartDate(): Carbon
|
||||
{
|
||||
return $this->leadReporting->getStartDate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the end date.
|
||||
*
|
||||
* @return \Carbon\Carbon
|
||||
*/
|
||||
public function getEndDate(): Carbon
|
||||
{
|
||||
return $this->leadReporting->getEndDate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns date range
|
||||
*/
|
||||
public function getDateRange(): string
|
||||
{
|
||||
return $this->getStartDate()->format('d M').' - '.$this->getEndDate()->format('d M');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,343 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Admin\Helpers\Reporting;
|
||||
|
||||
use Carbon\CarbonPeriod;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
abstract class AbstractReporting
|
||||
{
|
||||
/**
|
||||
* The starting date for a given period.
|
||||
*/
|
||||
protected Carbon $startDate;
|
||||
|
||||
/**
|
||||
* The ending date for a given period.
|
||||
*/
|
||||
protected Carbon $endDate;
|
||||
|
||||
/**
|
||||
* The starting date for the previous period.
|
||||
*/
|
||||
protected Carbon $lastStartDate;
|
||||
|
||||
/**
|
||||
* The ending date for the previous period.
|
||||
*/
|
||||
protected Carbon $lastEndDate;
|
||||
|
||||
/**
|
||||
* Create a helper instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->setStartDate(request()->date('start'));
|
||||
|
||||
$this->setEndDate(request()->date('end'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the start date or default to 30 days ago if not provided.
|
||||
*
|
||||
* @param \Carbon\Carbon|null $startDate
|
||||
* @return void
|
||||
*/
|
||||
public function setStartDate(?Carbon $startDate = null): self
|
||||
{
|
||||
$this->startDate = $startDate ? $startDate->startOfDay() : now()->subDays(30)->startOfDay();
|
||||
|
||||
$this->setLastStartDate();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the end date to the provided date's end of day, or to the current
|
||||
* date if not provided or if the provided date is in the future.
|
||||
*
|
||||
* @param \Carbon\Carbon|null $endDate
|
||||
* @return void
|
||||
*/
|
||||
public function setEndDate(?Carbon $endDate = null): self
|
||||
{
|
||||
$this->endDate = ($endDate && $endDate->endOfDay() <= now()) ? $endDate->endOfDay() : now();
|
||||
|
||||
$this->setLastEndDate();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the start date.
|
||||
*
|
||||
* @return \Carbon\Carbon
|
||||
*/
|
||||
public function getStartDate(): Carbon
|
||||
{
|
||||
return $this->startDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the end date.
|
||||
*
|
||||
* @return \Carbon\Carbon
|
||||
*/
|
||||
public function getEndDate(): Carbon
|
||||
{
|
||||
return $this->endDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the start date for the last period.
|
||||
*/
|
||||
private function setLastStartDate(): void
|
||||
{
|
||||
if (! isset($this->startDate)) {
|
||||
$this->setStartDate(request()->date('start'));
|
||||
}
|
||||
|
||||
if (! isset($this->endDate)) {
|
||||
$this->setEndDate(request()->date('end'));
|
||||
}
|
||||
|
||||
$this->lastStartDate = $this->startDate->clone()->subDays($this->startDate->diffInDays($this->endDate));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the end date for the last period.
|
||||
*/
|
||||
private function setLastEndDate(): void
|
||||
{
|
||||
$this->lastEndDate = $this->startDate->clone();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the last start date.
|
||||
*
|
||||
* @return \Carbon\Carbon
|
||||
*/
|
||||
public function getLastStartDate(): Carbon
|
||||
{
|
||||
return $this->lastStartDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the last end date.
|
||||
*
|
||||
* @return \Carbon\Carbon
|
||||
*/
|
||||
public function getLastEndDate(): Carbon
|
||||
{
|
||||
return $this->lastEndDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the percentage change between previous and current values.
|
||||
*
|
||||
* @param float|int $previous
|
||||
* @param float|int $current
|
||||
*/
|
||||
public function getPercentageChange($previous, $current): float|int
|
||||
{
|
||||
if (! $previous) {
|
||||
return $current ? 100 : 0;
|
||||
}
|
||||
|
||||
return ($current - $previous) / $previous * 100;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns time intervals.
|
||||
*
|
||||
* @param \Carbon\Carbon $startDate
|
||||
* @param \Carbon\Carbon $endDate
|
||||
* @param string $period
|
||||
* @return array
|
||||
*/
|
||||
public function getTimeInterval($startDate, $endDate, $dateColumn, $period)
|
||||
{
|
||||
if ($period == 'auto') {
|
||||
$totalMonths = $startDate->diffInMonths($endDate) + 1;
|
||||
|
||||
/**
|
||||
* If the difference between the start and end date is more than 5 months
|
||||
*/
|
||||
$intervals = $this->getMonthsInterval($startDate, $endDate);
|
||||
|
||||
if (! empty($intervals)) {
|
||||
return [
|
||||
'group_column' => "MONTH($dateColumn)",
|
||||
'intervals' => $intervals,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* If the difference between the start and end date is more than 6 weeks
|
||||
*/
|
||||
$intervals = $this->getWeeksInterval($startDate, $endDate);
|
||||
|
||||
if (! empty($intervals)) {
|
||||
return [
|
||||
'group_column' => "WEEK($dateColumn)",
|
||||
'intervals' => $intervals,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* If the difference between the start and end date is less than 6 weeks
|
||||
*/
|
||||
return [
|
||||
'group_column' => "DAYOFYEAR($dateColumn)",
|
||||
'intervals' => $this->getDaysInterval($startDate, $endDate),
|
||||
];
|
||||
} else {
|
||||
$datePeriod = CarbonPeriod::create($this->startDate, "1 $period", $this->endDate);
|
||||
|
||||
if ($period == 'year') {
|
||||
$formatter = '?';
|
||||
} elseif ($period == 'month') {
|
||||
$formatter = '?-?';
|
||||
} else {
|
||||
$formatter = '?-?-?';
|
||||
}
|
||||
|
||||
$groupColumn = 'DATE_FORMAT('.$dateColumn.', "'.Str::replaceArray('?', ['%Y', '%m', '%d'], $formatter).'")';
|
||||
|
||||
$intervals = [];
|
||||
|
||||
foreach ($datePeriod as $date) {
|
||||
$formattedDate = $date->format(Str::replaceArray('?', ['Y', 'm', 'd'], $formatter));
|
||||
|
||||
$intervals[] = [
|
||||
'filter' => $formattedDate,
|
||||
'start' => $formattedDate,
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
'group_column' => $groupColumn,
|
||||
'intervals' => $intervals,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns time intervals.
|
||||
*
|
||||
* @param \Carbon\Carbon $startDate
|
||||
* @param \Carbon\Carbon $endDate
|
||||
* @return array
|
||||
*/
|
||||
public function getMonthsInterval($startDate, $endDate)
|
||||
{
|
||||
$intervals = [];
|
||||
|
||||
$totalMonths = $startDate->diffInMonths($endDate) + 1;
|
||||
|
||||
/**
|
||||
* If the difference between the start and end date is less than 5 months
|
||||
*/
|
||||
if ($totalMonths <= 5) {
|
||||
return $intervals;
|
||||
}
|
||||
|
||||
for ($i = 0; $i < $totalMonths; $i++) {
|
||||
$intervalStartDate = clone $startDate;
|
||||
|
||||
$intervalStartDate->addMonths($i);
|
||||
|
||||
$start = $intervalStartDate->startOfDay();
|
||||
|
||||
$end = ($totalMonths - 1 == $i)
|
||||
? $endDate
|
||||
: $intervalStartDate->addMonth()->subDay()->endOfDay();
|
||||
|
||||
$intervals[] = [
|
||||
'filter' => $start->month,
|
||||
'start' => $start->format('d M'),
|
||||
'end' => $end->format('d M'),
|
||||
];
|
||||
}
|
||||
|
||||
return $intervals;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns time intervals.
|
||||
*
|
||||
* @param \Carbon\Carbon $startDate
|
||||
* @param \Carbon\Carbon $endDate
|
||||
* @return array
|
||||
*/
|
||||
public function getWeeksInterval($startDate, $endDate)
|
||||
{
|
||||
$intervals = [];
|
||||
|
||||
$startWeekDay = Carbon::createFromTimeString(core()->xWeekRange($startDate, 0).' 00:00:01');
|
||||
|
||||
$endWeekDay = Carbon::createFromTimeString(core()->xWeekRange($endDate, 1).' 23:59:59');
|
||||
|
||||
$totalWeeks = $startWeekDay->diffInWeeks($endWeekDay);
|
||||
|
||||
/**
|
||||
* If the difference between the start and end date is less than 6 weeks
|
||||
*/
|
||||
if ($totalWeeks <= 6) {
|
||||
return $intervals;
|
||||
}
|
||||
|
||||
for ($i = 0; $i < $totalWeeks; $i++) {
|
||||
$intervalStartDate = clone $startDate;
|
||||
|
||||
$intervalStartDate->addWeeks($i);
|
||||
|
||||
$start = $i == 0
|
||||
? $startDate
|
||||
: Carbon::createFromTimeString(core()->xWeekRange($intervalStartDate, 0).' 00:00:01');
|
||||
|
||||
$end = ($totalWeeks - 1 == $i)
|
||||
? $endDate
|
||||
: Carbon::createFromTimeString(core()->xWeekRange($intervalStartDate->subDay(), 1).' 23:59:59');
|
||||
|
||||
$intervals[] = [
|
||||
'filter' => $start->week,
|
||||
'start' => $start->format('d M'),
|
||||
'end' => $end->format('d M'),
|
||||
];
|
||||
}
|
||||
|
||||
return $intervals;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns time intervals.
|
||||
*
|
||||
* @param \Carbon\Carbon $startDate
|
||||
* @param \Carbon\Carbon $endDate
|
||||
* @return array
|
||||
*/
|
||||
public function getDaysInterval($startDate, $endDate)
|
||||
{
|
||||
$intervals = [];
|
||||
|
||||
$totalDays = $startDate->diffInDays($endDate) + 1;
|
||||
|
||||
for ($i = 0; $i < $totalDays; $i++) {
|
||||
$intervalStartDate = clone $startDate;
|
||||
|
||||
$intervalStartDate->addDays($i);
|
||||
|
||||
$intervals[] = [
|
||||
'filter' => $intervalStartDate->dayOfYear,
|
||||
'start' => $intervalStartDate->startOfDay()->format('d M'),
|
||||
'end' => $intervalStartDate->endOfDay()->format('d M'),
|
||||
];
|
||||
}
|
||||
|
||||
return $intervals;
|
||||
}
|
||||
}
|
||||
5
packages/Webkul/Admin/src/Helpers/Reporting/Activity.php
Normal file
5
packages/Webkul/Admin/src/Helpers/Reporting/Activity.php
Normal file
@@ -0,0 +1,5 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Admin\Helpers\Reporting;
|
||||
|
||||
class Activity extends AbstractReporting {}
|
||||
483
packages/Webkul/Admin/src/Helpers/Reporting/Lead.php
Normal file
483
packages/Webkul/Admin/src/Helpers/Reporting/Lead.php
Normal file
@@ -0,0 +1,483 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Admin\Helpers\Reporting;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Webkul\Lead\Repositories\LeadRepository;
|
||||
use Webkul\Lead\Repositories\StageRepository;
|
||||
|
||||
class Lead extends AbstractReporting
|
||||
{
|
||||
/**
|
||||
* The channel ids.
|
||||
*/
|
||||
protected array $stageIds;
|
||||
|
||||
/**
|
||||
* The all stage ids.
|
||||
*/
|
||||
protected array $allStageIds;
|
||||
|
||||
/**
|
||||
* The won stage ids.
|
||||
*/
|
||||
protected array $wonStageIds;
|
||||
|
||||
/**
|
||||
* The lost stage ids.
|
||||
*/
|
||||
protected array $lostStageIds;
|
||||
|
||||
/**
|
||||
* Create a helper instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(
|
||||
protected LeadRepository $leadRepository,
|
||||
protected StageRepository $stageRepository
|
||||
) {
|
||||
$this->allStageIds = $this->stageRepository->pluck('id')->toArray();
|
||||
|
||||
$this->wonStageIds = $this->stageRepository->where('code', 'won')->pluck('id')->toArray();
|
||||
|
||||
$this->lostStageIds = $this->stageRepository->where('code', 'lost')->pluck('id')->toArray();
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns current customers over time
|
||||
*
|
||||
* @param string $period
|
||||
*/
|
||||
public function getTotalLeadsOverTime($period = 'auto'): array
|
||||
{
|
||||
$this->stageIds = $this->allStageIds;
|
||||
|
||||
$period = $this->determinePeriod($period);
|
||||
|
||||
return $this->getOverTimeStats($this->startDate, $this->endDate, 'leads.id', 'created_at', $period);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns current customers over time
|
||||
*
|
||||
* @param string $period
|
||||
*/
|
||||
public function getTotalWonLeadsOverTime($period = 'auto'): array
|
||||
{
|
||||
$this->stageIds = $this->wonStageIds;
|
||||
|
||||
$period = $this->determinePeriod($period);
|
||||
|
||||
return $this->getOverTimeStats($this->startDate, $this->endDate, 'leads.id', 'closed_at', $period);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns current customers over time
|
||||
*
|
||||
* @param string $period
|
||||
*/
|
||||
public function getTotalLostLeadsOverTime($period = 'auto'): array
|
||||
{
|
||||
$this->stageIds = $this->lostStageIds;
|
||||
|
||||
$period = $this->determinePeriod($period);
|
||||
|
||||
return $this->getOverTimeStats($this->startDate, $this->endDate, 'leads.id', 'closed_at', $period);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the appropriate period based on date range
|
||||
*
|
||||
* @param string $period
|
||||
*/
|
||||
protected function determinePeriod($period = 'auto'): string
|
||||
{
|
||||
if ($period !== 'auto') {
|
||||
return $period;
|
||||
}
|
||||
|
||||
$diffInDays = $this->startDate->diffInDays($this->endDate);
|
||||
$diffInMonths = $this->startDate->diffInMonths($this->endDate);
|
||||
$diffInYears = $this->startDate->diffInYears($this->endDate);
|
||||
|
||||
if ($diffInYears > 3) {
|
||||
return 'year';
|
||||
} elseif ($diffInMonths > 6) {
|
||||
return 'month';
|
||||
} elseif ($diffInDays > 60) {
|
||||
return 'week';
|
||||
} else {
|
||||
return 'day';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves total leads and their progress.
|
||||
*/
|
||||
public function getTotalLeadsProgress(): array
|
||||
{
|
||||
return [
|
||||
'previous' => $previous = $this->getTotalLeads($this->lastStartDate, $this->lastEndDate),
|
||||
'current' => $current = $this->getTotalLeads($this->startDate, $this->endDate),
|
||||
'progress' => $this->getPercentageChange($previous, $current),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves total leads by date
|
||||
*
|
||||
* @param \Carbon\Carbon $startDate
|
||||
* @param \Carbon\Carbon $endDate
|
||||
*/
|
||||
public function getTotalLeads($startDate, $endDate): int
|
||||
{
|
||||
return $this->leadRepository
|
||||
->resetModel()
|
||||
->whereBetween('created_at', [$startDate, $endDate])
|
||||
->count();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves average leads per day and their progress.
|
||||
*/
|
||||
public function getAverageLeadsPerDayProgress(): array
|
||||
{
|
||||
return [
|
||||
'previous' => $previous = $this->getAverageLeadsPerDay($this->lastStartDate, $this->lastEndDate),
|
||||
'current' => $current = $this->getAverageLeadsPerDay($this->startDate, $this->endDate),
|
||||
'progress' => $this->getPercentageChange($previous, $current),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves average leads per day
|
||||
*
|
||||
* @param \Carbon\Carbon $startDate
|
||||
* @param \Carbon\Carbon $endDate
|
||||
*/
|
||||
public function getAverageLeadsPerDay($startDate, $endDate): float
|
||||
{
|
||||
$days = $startDate->diffInDays($endDate);
|
||||
|
||||
if ($days == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return $this->getTotalLeads($startDate, $endDate) / $days;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves total lead value and their progress.
|
||||
*/
|
||||
public function getTotalLeadValueProgress(): array
|
||||
{
|
||||
return [
|
||||
'previous' => $previous = $this->getTotalLeadValue($this->lastStartDate, $this->lastEndDate),
|
||||
'current' => $current = $this->getTotalLeadValue($this->startDate, $this->endDate),
|
||||
'formatted_total' => core()->formatBasePrice($current),
|
||||
'progress' => $this->getPercentageChange($previous, $current),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves total lead value
|
||||
*
|
||||
* @param \Carbon\Carbon $startDate
|
||||
* @param \Carbon\Carbon $endDate
|
||||
*/
|
||||
public function getTotalLeadValue($startDate, $endDate): float
|
||||
{
|
||||
return $this->leadRepository
|
||||
->resetModel()
|
||||
->whereBetween('created_at', [$startDate, $endDate])
|
||||
->sum('lead_value');
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves average lead value and their progress.
|
||||
*/
|
||||
public function getAverageLeadValueProgress(): array
|
||||
{
|
||||
return [
|
||||
'previous' => $previous = $this->getAverageLeadValue($this->lastStartDate, $this->lastEndDate),
|
||||
'current' => $current = $this->getAverageLeadValue($this->startDate, $this->endDate),
|
||||
'formatted_total' => core()->formatBasePrice($current),
|
||||
'progress' => $this->getPercentageChange($previous, $current),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves average lead value
|
||||
*
|
||||
* @param \Carbon\Carbon $startDate
|
||||
* @param \Carbon\Carbon $endDate
|
||||
*/
|
||||
public function getAverageLeadValue($startDate, $endDate): float
|
||||
{
|
||||
return $this->leadRepository
|
||||
->resetModel()
|
||||
->whereBetween('created_at', [$startDate, $endDate])
|
||||
->avg('lead_value') ?? 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves total won lead value and their progress.
|
||||
*/
|
||||
public function getTotalWonLeadValueProgress(): array
|
||||
{
|
||||
return [
|
||||
'previous' => $previous = $this->getTotalWonLeadValue($this->lastStartDate, $this->lastEndDate),
|
||||
'current' => $current = $this->getTotalWonLeadValue($this->startDate, $this->endDate),
|
||||
'formatted_total' => core()->formatBasePrice($current),
|
||||
'progress' => $this->getPercentageChange($previous, $current),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves average won lead value
|
||||
*
|
||||
* @param \Carbon\Carbon $startDate
|
||||
* @param \Carbon\Carbon $endDate
|
||||
* @return array
|
||||
*/
|
||||
public function getTotalWonLeadValue($startDate, $endDate): ?float
|
||||
{
|
||||
return $this->leadRepository
|
||||
->resetModel()
|
||||
->whereIn('lead_pipeline_stage_id', $this->wonStageIds)
|
||||
->whereBetween('created_at', [$startDate, $endDate])
|
||||
->sum('lead_value');
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves average lost lead value and their progress.
|
||||
*/
|
||||
public function getTotalLostLeadValueProgress(): array
|
||||
{
|
||||
return [
|
||||
'previous' => $previous = $this->getTotalLostLeadValue($this->lastStartDate, $this->lastEndDate),
|
||||
'current' => $current = $this->getTotalLostLeadValue($this->startDate, $this->endDate),
|
||||
'formatted_total' => core()->formatBasePrice($current),
|
||||
'progress' => $this->getPercentageChange($previous, $current),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves average lost lead value
|
||||
*
|
||||
* @param \Carbon\Carbon $startDate
|
||||
* @param \Carbon\Carbon $endDate
|
||||
* @return array
|
||||
*/
|
||||
public function getTotalLostLeadValue($startDate, $endDate): ?float
|
||||
{
|
||||
return $this->leadRepository
|
||||
->resetModel()
|
||||
->whereIn('lead_pipeline_stage_id', $this->lostStageIds)
|
||||
->whereBetween('created_at', [$startDate, $endDate])
|
||||
->sum('lead_value');
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves total lead value by sources.
|
||||
*/
|
||||
public function getTotalWonLeadValueBySources()
|
||||
{
|
||||
return $this->leadRepository
|
||||
->resetModel()
|
||||
->select(
|
||||
'lead_sources.name',
|
||||
DB::raw('SUM(lead_value) as total')
|
||||
)
|
||||
->leftJoin('lead_sources', 'leads.lead_source_id', '=', 'lead_sources.id')
|
||||
->whereIn('lead_pipeline_stage_id', $this->wonStageIds)
|
||||
->whereBetween('leads.created_at', [$this->startDate, $this->endDate])
|
||||
->groupBy('lead_source_id')
|
||||
->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves total lead value by types.
|
||||
*/
|
||||
public function getTotalWonLeadValueByTypes()
|
||||
{
|
||||
return $this->leadRepository
|
||||
->resetModel()
|
||||
->select(
|
||||
'lead_types.name',
|
||||
DB::raw('SUM(lead_value) as total')
|
||||
)
|
||||
->leftJoin('lead_types', 'leads.lead_type_id', '=', 'lead_types.id')
|
||||
->whereIn('lead_pipeline_stage_id', $this->wonStageIds)
|
||||
->whereBetween('leads.created_at', [$this->startDate, $this->endDate])
|
||||
->groupBy('lead_type_id')
|
||||
->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves open leads by states.
|
||||
*/
|
||||
public function getOpenLeadsByStates()
|
||||
{
|
||||
return $this->leadRepository
|
||||
->resetModel()
|
||||
->select(
|
||||
'lead_pipeline_stages.name',
|
||||
DB::raw('COUNT(lead_value) as total')
|
||||
)
|
||||
->leftJoin('lead_pipeline_stages', 'leads.lead_pipeline_stage_id', '=', 'lead_pipeline_stages.id')
|
||||
->whereNotIn('lead_pipeline_stage_id', $this->wonStageIds)
|
||||
->whereNotIn('lead_pipeline_stage_id', $this->lostStageIds)
|
||||
->whereBetween('leads.created_at', [$this->startDate, $this->endDate])
|
||||
->groupBy('lead_pipeline_stage_id')
|
||||
->orderByDesc('total')
|
||||
->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns over time stats.
|
||||
*
|
||||
* @param \Carbon\Carbon $startDate
|
||||
* @param \Carbon\Carbon $endDate
|
||||
* @param string $valueColumn
|
||||
* @param string $dateColumn
|
||||
* @param string $period
|
||||
*/
|
||||
public function getOverTimeStats($startDate, $endDate, $valueColumn, $dateColumn = 'created_at', $period = 'auto'): array
|
||||
{
|
||||
$period = $this->determinePeriod($period);
|
||||
|
||||
$intervals = $this->generateTimeIntervals($startDate, $endDate, $period);
|
||||
|
||||
$groupColumn = $this->getGroupColumn($dateColumn, $period);
|
||||
|
||||
$query = $this->leadRepository
|
||||
->resetModel()
|
||||
->select(
|
||||
DB::raw("$groupColumn AS date"),
|
||||
DB::raw('COUNT(DISTINCT id) AS count'),
|
||||
DB::raw('SUM('.\DB::getTablePrefix()."$valueColumn) AS total")
|
||||
)
|
||||
->whereIn('lead_pipeline_stage_id', $this->stageIds)
|
||||
->whereBetween($dateColumn, [$startDate, $endDate])
|
||||
->groupBy(DB::raw($groupColumn))
|
||||
->orderBy(DB::raw($groupColumn));
|
||||
|
||||
$results = $query->get();
|
||||
$resultLookup = $results->keyBy('date');
|
||||
|
||||
$stats = [];
|
||||
|
||||
foreach ($intervals as $interval) {
|
||||
$result = $resultLookup->get($interval['key']);
|
||||
|
||||
$stats[] = [
|
||||
'label' => $interval['label'],
|
||||
'count' => $result ? (int) $result->count : 0,
|
||||
'total' => $result ? (float) $result->total : 0,
|
||||
];
|
||||
}
|
||||
|
||||
return $stats;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate time intervals based on period
|
||||
*/
|
||||
protected function generateTimeIntervals(Carbon $startDate, Carbon $endDate, string $period): array
|
||||
{
|
||||
$intervals = [];
|
||||
$current = $startDate->copy();
|
||||
|
||||
while ($current <= $endDate) {
|
||||
$interval = [
|
||||
'key' => $this->formatDateForGrouping($current, $period),
|
||||
'label' => $this->formatDateForLabel($current, $period),
|
||||
];
|
||||
|
||||
$intervals[] = $interval;
|
||||
|
||||
switch ($period) {
|
||||
case 'day':
|
||||
$current->addDay();
|
||||
|
||||
break;
|
||||
case 'week':
|
||||
$current->addWeek();
|
||||
|
||||
break;
|
||||
case 'month':
|
||||
$current->addMonth();
|
||||
|
||||
break;
|
||||
case 'year':
|
||||
$current->addYear();
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $intervals;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the SQL group column based on period
|
||||
*/
|
||||
protected function getGroupColumn(string $dateColumn, string $period): string
|
||||
{
|
||||
switch ($period) {
|
||||
case 'day':
|
||||
return "DATE($dateColumn)";
|
||||
case 'week':
|
||||
return "DATE_FORMAT($dateColumn, '%Y-%u')";
|
||||
case 'month':
|
||||
return "DATE_FORMAT($dateColumn, '%Y-%m')";
|
||||
case 'year':
|
||||
return "YEAR($dateColumn)";
|
||||
default:
|
||||
return "DATE($dateColumn)";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Format date for grouping key
|
||||
*/
|
||||
protected function formatDateForGrouping(Carbon $date, string $period): string
|
||||
{
|
||||
switch ($period) {
|
||||
case 'day':
|
||||
return $date->format('Y-m-d');
|
||||
case 'week':
|
||||
return $date->format('Y-W');
|
||||
case 'month':
|
||||
return $date->format('Y-m');
|
||||
case 'year':
|
||||
return $date->format('Y');
|
||||
default:
|
||||
return $date->format('Y-m-d');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Format date for display label
|
||||
*/
|
||||
protected function formatDateForLabel(Carbon $date, string $period): string
|
||||
{
|
||||
switch ($period) {
|
||||
case 'day':
|
||||
return $date->format('M d');
|
||||
case 'week':
|
||||
return 'Week '.$date->format('W, Y');
|
||||
case 'month':
|
||||
return $date->format('M Y');
|
||||
case 'year':
|
||||
return $date->format('Y');
|
||||
default:
|
||||
return $date->format('M d');
|
||||
}
|
||||
}
|
||||
}
|
||||
80
packages/Webkul/Admin/src/Helpers/Reporting/Organization.php
Normal file
80
packages/Webkul/Admin/src/Helpers/Reporting/Organization.php
Normal file
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Admin\Helpers\Reporting;
|
||||
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Webkul\Contact\Repositories\OrganizationRepository;
|
||||
|
||||
class Organization extends AbstractReporting
|
||||
{
|
||||
/**
|
||||
* Create a helper instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(protected OrganizationRepository $organizationRepository)
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves total organizations and their progress.
|
||||
*/
|
||||
public function getTotalOrganizationsProgress(): array
|
||||
{
|
||||
return [
|
||||
'previous' => $previous = $this->getTotalOrganizations($this->lastStartDate, $this->lastEndDate),
|
||||
'current' => $current = $this->getTotalOrganizations($this->startDate, $this->endDate),
|
||||
'progress' => $this->getPercentageChange($previous, $current),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves total organizations by date
|
||||
*
|
||||
* @param \Carbon\Carbon $startDate
|
||||
* @param \Carbon\Carbon $endDate
|
||||
*/
|
||||
public function getTotalOrganizations($startDate, $endDate): int
|
||||
{
|
||||
return $this->organizationRepository
|
||||
->resetModel()
|
||||
->whereBetween('created_at', [$startDate, $endDate])
|
||||
->count();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets top customers by revenue.
|
||||
*
|
||||
* @param int $limit
|
||||
*/
|
||||
public function getTopOrganizationsByRevenue($limit = null): Collection
|
||||
{
|
||||
$tablePrefix = DB::getTablePrefix();
|
||||
|
||||
$items = $this->organizationRepository
|
||||
->resetModel()
|
||||
->leftJoin('persons', 'organizations.id', '=', 'persons.organization_id')
|
||||
->leftJoin('leads', 'persons.id', '=', 'leads.person_id')
|
||||
->select('*', 'persons.id as id')
|
||||
->addSelect(DB::raw('SUM('.$tablePrefix.'leads.lead_value) as revenue'))
|
||||
->whereBetween('leads.closed_at', [$this->startDate, $this->endDate])
|
||||
->having(DB::raw('SUM('.$tablePrefix.'leads.lead_value)'), '>', 0)
|
||||
->groupBy('organization_id')
|
||||
->orderBy('revenue', 'DESC')
|
||||
->limit($limit)
|
||||
->get();
|
||||
|
||||
$items = $items->map(function ($item) {
|
||||
return [
|
||||
'id' => $item->id,
|
||||
'name' => $item->name,
|
||||
'revenue' => $item->revenue,
|
||||
'formatted_revenue' => core()->formatBasePrice($item->revenue),
|
||||
];
|
||||
});
|
||||
|
||||
return $items;
|
||||
}
|
||||
}
|
||||
81
packages/Webkul/Admin/src/Helpers/Reporting/Person.php
Normal file
81
packages/Webkul/Admin/src/Helpers/Reporting/Person.php
Normal file
@@ -0,0 +1,81 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Admin\Helpers\Reporting;
|
||||
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Webkul\Contact\Repositories\PersonRepository;
|
||||
|
||||
class Person extends AbstractReporting
|
||||
{
|
||||
/**
|
||||
* Create a helper instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(protected PersonRepository $personRepository)
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves total persons and their progress.
|
||||
*/
|
||||
public function getTotalPersonsProgress(): array
|
||||
{
|
||||
return [
|
||||
'previous' => $previous = $this->getTotalPersons($this->lastStartDate, $this->lastEndDate),
|
||||
'current' => $current = $this->getTotalPersons($this->startDate, $this->endDate),
|
||||
'progress' => $this->getPercentageChange($previous, $current),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves total persons by date
|
||||
*
|
||||
* @param \Carbon\Carbon $startDate
|
||||
* @param \Carbon\Carbon $endDate
|
||||
*/
|
||||
public function getTotalPersons($startDate, $endDate): int
|
||||
{
|
||||
return $this->personRepository
|
||||
->resetModel()
|
||||
->whereBetween('created_at', [$startDate, $endDate])
|
||||
->count();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets top customers by revenue.
|
||||
*
|
||||
* @param int $limit
|
||||
*/
|
||||
public function getTopCustomersByRevenue($limit = null): Collection
|
||||
{
|
||||
$tablePrefix = DB::getTablePrefix();
|
||||
|
||||
$items = $this->personRepository
|
||||
->resetModel()
|
||||
->leftJoin('leads', 'persons.id', '=', 'leads.person_id')
|
||||
->select('*', 'persons.id as id')
|
||||
->addSelect(DB::raw('SUM('.$tablePrefix.'leads.lead_value) as revenue'))
|
||||
->whereBetween('leads.closed_at', [$this->startDate, $this->endDate])
|
||||
->having(DB::raw('SUM('.$tablePrefix.'leads.lead_value)'), '>', 0)
|
||||
->groupBy('person_id')
|
||||
->orderBy('revenue', 'DESC')
|
||||
->limit($limit)
|
||||
->get();
|
||||
|
||||
$items = $items->map(function ($item) {
|
||||
return [
|
||||
'id' => $item->id,
|
||||
'name' => $item->name,
|
||||
'emails' => $item->emails,
|
||||
'contact_numbers' => $item->contact_numbers,
|
||||
'revenue' => $item->revenue,
|
||||
'formatted_revenue' => core()->formatBasePrice($item->revenue),
|
||||
];
|
||||
});
|
||||
|
||||
return $items;
|
||||
}
|
||||
}
|
||||
94
packages/Webkul/Admin/src/Helpers/Reporting/Product.php
Normal file
94
packages/Webkul/Admin/src/Helpers/Reporting/Product.php
Normal file
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Admin\Helpers\Reporting;
|
||||
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Webkul\Lead\Repositories\ProductRepository;
|
||||
|
||||
class Product extends AbstractReporting
|
||||
{
|
||||
/**
|
||||
* Create a helper instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(
|
||||
protected ProductRepository $productRepository
|
||||
) {
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets top-selling products by revenue.
|
||||
*
|
||||
* @param int $limit
|
||||
*/
|
||||
public function getTopSellingProductsByRevenue($limit = null): Collection
|
||||
{
|
||||
$tablePrefix = DB::getTablePrefix();
|
||||
|
||||
$items = $this->productRepository
|
||||
->resetModel()
|
||||
->with('product')
|
||||
->leftJoin('leads', 'lead_products.lead_id', '=', 'leads.id')
|
||||
->leftJoin('products', 'lead_products.product_id', '=', 'products.id')
|
||||
->select('*')
|
||||
->addSelect(DB::raw('SUM('.$tablePrefix.'lead_products.amount) as revenue'))
|
||||
->whereBetween('leads.closed_at', [$this->startDate, $this->endDate])
|
||||
->having(DB::raw('SUM('.$tablePrefix.'lead_products.amount)'), '>', 0)
|
||||
->groupBy('product_id')
|
||||
->orderBy('revenue', 'DESC')
|
||||
->limit($limit)
|
||||
->get();
|
||||
|
||||
$items = $items->map(function ($item) {
|
||||
return [
|
||||
'id' => $item->product_id,
|
||||
'name' => $item->name,
|
||||
'price' => $item->product?->price,
|
||||
'formatted_price' => core()->formatBasePrice($item->price),
|
||||
'revenue' => $item->revenue,
|
||||
'formatted_revenue' => core()->formatBasePrice($item->revenue),
|
||||
];
|
||||
});
|
||||
|
||||
return $items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets top-selling products by quantity.
|
||||
*
|
||||
* @param int $limit
|
||||
*/
|
||||
public function getTopSellingProductsByQuantity($limit = null): Collection
|
||||
{
|
||||
$tablePrefix = DB::getTablePrefix();
|
||||
|
||||
$items = $this->productRepository
|
||||
->resetModel()
|
||||
->with('product')
|
||||
->leftJoin('leads', 'lead_products.lead_id', '=', 'leads.id')
|
||||
->leftJoin('products', 'lead_products.product_id', '=', 'products.id')
|
||||
->select('*')
|
||||
->addSelect(DB::raw('SUM('.$tablePrefix.'lead_products.quantity) as total_qty_ordered'))
|
||||
->whereBetween('leads.closed_at', [$this->startDate, $this->endDate])
|
||||
->having(DB::raw('SUM('.$tablePrefix.'lead_products.quantity)'), '>', 0)
|
||||
->groupBy('product_id')
|
||||
->orderBy('total_qty_ordered', 'DESC')
|
||||
->limit($limit)
|
||||
->get();
|
||||
|
||||
$items = $items->map(function ($item) {
|
||||
return [
|
||||
'id' => $item->product_id,
|
||||
'name' => $item->name,
|
||||
'price' => $item->product?->price,
|
||||
'formatted_price' => core()->formatBasePrice($item->price),
|
||||
'total_qty_ordered' => $item->total_qty_ordered,
|
||||
];
|
||||
});
|
||||
|
||||
return $items;
|
||||
}
|
||||
}
|
||||
44
packages/Webkul/Admin/src/Helpers/Reporting/Quote.php
Normal file
44
packages/Webkul/Admin/src/Helpers/Reporting/Quote.php
Normal file
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Admin\Helpers\Reporting;
|
||||
|
||||
use Webkul\Quote\Repositories\QuoteRepository;
|
||||
|
||||
class Quote extends AbstractReporting
|
||||
{
|
||||
/**
|
||||
* Create a helper instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(protected QuoteRepository $quoteRepository)
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves total quotes and their progress.
|
||||
*/
|
||||
public function getTotalQuotesProgress(): array
|
||||
{
|
||||
return [
|
||||
'previous' => $previous = $this->getTotalQuotes($this->lastStartDate, $this->lastEndDate),
|
||||
'current' => $current = $this->getTotalQuotes($this->startDate, $this->endDate),
|
||||
'progress' => $this->getPercentageChange($previous, $current),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves total quotes by date
|
||||
*
|
||||
* @param \Carbon\Carbon $startDate
|
||||
* @param \Carbon\Carbon $endDate
|
||||
*/
|
||||
public function getTotalQuotes($startDate, $endDate): int
|
||||
{
|
||||
return $this->quoteRepository
|
||||
->resetModel()
|
||||
->whereBetween('created_at', [$startDate, $endDate])
|
||||
->count();
|
||||
}
|
||||
}
|
||||
261
packages/Webkul/Admin/src/Http/Controllers/Activity/ActivityController.php
Executable file
261
packages/Webkul/Admin/src/Http/Controllers/Activity/ActivityController.php
Executable file
@@ -0,0 +1,261 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Admin\Http\Controllers\Activity;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Support\Facades\Event;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\View\View;
|
||||
use Symfony\Component\HttpFoundation\RedirectResponse;
|
||||
use Symfony\Component\HttpFoundation\StreamedResponse;
|
||||
use Webkul\Activity\Repositories\ActivityRepository;
|
||||
use Webkul\Activity\Repositories\FileRepository;
|
||||
use Webkul\Admin\DataGrids\Activity\ActivityDataGrid;
|
||||
use Webkul\Admin\Http\Controllers\Controller;
|
||||
use Webkul\Admin\Http\Requests\MassDestroyRequest;
|
||||
use Webkul\Admin\Http\Requests\MassUpdateRequest;
|
||||
use Webkul\Admin\Http\Resources\ActivityResource;
|
||||
use Webkul\Attribute\Repositories\AttributeRepository;
|
||||
|
||||
class ActivityController extends Controller
|
||||
{
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(
|
||||
protected ActivityRepository $activityRepository,
|
||||
protected FileRepository $fileRepository,
|
||||
protected AttributeRepository $attributeRepository,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*/
|
||||
public function index(): View
|
||||
{
|
||||
return view('admin::activities.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a listing of the resource.
|
||||
*/
|
||||
public function get(): JsonResponse
|
||||
{
|
||||
if (! request()->has('view_type')) {
|
||||
return datagrid(ActivityDataGrid::class)->process();
|
||||
}
|
||||
|
||||
$startDate = request()->get('startDate')
|
||||
? Carbon::createFromTimeString(request()->get('startDate').' 00:00:01')
|
||||
: Carbon::now()->startOfWeek()->format('Y-m-d H:i:s');
|
||||
|
||||
$endDate = request()->get('endDate')
|
||||
? Carbon::createFromTimeString(request()->get('endDate').' 23:59:59')
|
||||
: Carbon::now()->endOfWeek()->format('Y-m-d H:i:s');
|
||||
|
||||
$activities = $this->activityRepository->getActivities([$startDate, $endDate])->toArray();
|
||||
|
||||
return response()->json([
|
||||
'activities' => $activities,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*/
|
||||
public function store(): RedirectResponse|JsonResponse
|
||||
{
|
||||
$this->validate(request(), [
|
||||
'type' => 'required',
|
||||
'comment' => 'required_if:type,note',
|
||||
'schedule_from' => 'required_unless:type,note,file',
|
||||
'schedule_to' => 'required_unless:type,note,file',
|
||||
'file' => 'required_if:type,file',
|
||||
]);
|
||||
|
||||
if (request('type') === 'meeting') {
|
||||
/**
|
||||
* Check if meeting is overlapping with other meetings.
|
||||
*/
|
||||
$isOverlapping = $this->activityRepository->isDurationOverlapping(
|
||||
request()->input('schedule_from'),
|
||||
request()->input('schedule_to'),
|
||||
request()->input('participants'),
|
||||
request()->input('id')
|
||||
);
|
||||
|
||||
if ($isOverlapping) {
|
||||
if (request()->ajax()) {
|
||||
return response()->json([
|
||||
'message' => trans('admin::app.activities.overlapping-error'),
|
||||
], 400);
|
||||
}
|
||||
|
||||
session()->flash('success', trans('admin::app.activities.overlapping-error'));
|
||||
|
||||
return redirect()->back();
|
||||
}
|
||||
}
|
||||
|
||||
Event::dispatch('activity.create.before');
|
||||
|
||||
$activity = $this->activityRepository->create(array_merge(request()->all(), [
|
||||
'is_done' => request('type') == 'note' ? 1 : 0,
|
||||
'user_id' => auth()->guard('user')->user()->id,
|
||||
]));
|
||||
|
||||
Event::dispatch('activity.create.after', $activity);
|
||||
|
||||
if (request()->ajax()) {
|
||||
return response()->json([
|
||||
'data' => new ActivityResource($activity),
|
||||
'message' => trans('admin::app.activities.create-success'),
|
||||
]);
|
||||
}
|
||||
|
||||
session()->flash('success', trans('admin::app.activities.create-success'));
|
||||
|
||||
return redirect()->back();
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*/
|
||||
public function edit(int $id): View
|
||||
{
|
||||
$activity = $this->activityRepository->findOrFail($id);
|
||||
|
||||
$leadId = old('lead_id') ?? optional($activity->leads()->first())->id;
|
||||
|
||||
$lookUpEntityData = $this->attributeRepository->getLookUpEntity('leads', $leadId);
|
||||
|
||||
return view('admin::activities.edit', compact('activity', 'lookUpEntityData'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*/
|
||||
public function update($id): RedirectResponse|JsonResponse
|
||||
{
|
||||
Event::dispatch('activity.update.before', $id);
|
||||
|
||||
$data = request()->all();
|
||||
|
||||
$activity = $this->activityRepository->update($data, $id);
|
||||
|
||||
/**
|
||||
* We will not use `empty` directly here because `lead_id` can be a blank string
|
||||
* from the activity form. However, on the activity view page, we are only updating the
|
||||
* `is_done` field, so `lead_id` will not be present in that case.
|
||||
*/
|
||||
if (isset($data['lead_id'])) {
|
||||
$activity->leads()->sync(
|
||||
! empty($data['lead_id'])
|
||||
? [$data['lead_id']]
|
||||
: []
|
||||
);
|
||||
}
|
||||
|
||||
Event::dispatch('activity.update.after', $activity);
|
||||
|
||||
if (request()->ajax()) {
|
||||
return response()->json([
|
||||
'data' => new ActivityResource($activity),
|
||||
'message' => trans('admin::app.activities.update-success'),
|
||||
]);
|
||||
}
|
||||
|
||||
session()->flash('success', trans('admin::app.activities.update-success'));
|
||||
|
||||
return redirect()->route('admin.activities.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Mass Update the specified resources.
|
||||
*/
|
||||
public function massUpdate(MassUpdateRequest $massUpdateRequest): JsonResponse
|
||||
{
|
||||
$activities = $this->activityRepository->findWhereIn('id', $massUpdateRequest->input('indices'));
|
||||
|
||||
foreach ($activities as $activity) {
|
||||
Event::dispatch('activity.update.before', $activity->id);
|
||||
|
||||
$activity = $this->activityRepository->update([
|
||||
'is_done' => $massUpdateRequest->input('value'),
|
||||
], $activity->id);
|
||||
|
||||
Event::dispatch('activity.update.after', $activity);
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'message' => trans('admin::app.activities.mass-update-success'),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Download file from storage.
|
||||
*/
|
||||
public function download(int $id): StreamedResponse
|
||||
{
|
||||
try {
|
||||
$file = $this->fileRepository->findOrFail($id);
|
||||
|
||||
return Storage::download($file->path);
|
||||
} catch (\Exception $exception) {
|
||||
abort(404);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove the specified resource from storage.
|
||||
*/
|
||||
public function destroy(int $id): JsonResponse
|
||||
{
|
||||
$activity = $this->activityRepository->findOrFail($id);
|
||||
|
||||
try {
|
||||
Event::dispatch('activity.delete.before', $id);
|
||||
|
||||
$activity?->delete($id);
|
||||
|
||||
Event::dispatch('activity.delete.after', $id);
|
||||
|
||||
return response()->json([
|
||||
'message' => trans('admin::app.activities.destroy-success'),
|
||||
], 200);
|
||||
} catch (\Exception $exception) {
|
||||
return response()->json([
|
||||
'message' => trans('admin::app.activities.destroy-failed'),
|
||||
], 400);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mass Delete the specified resources.
|
||||
*/
|
||||
public function massDestroy(MassDestroyRequest $massDestroyRequest): JsonResponse
|
||||
{
|
||||
$activities = $this->activityRepository->findWhereIn('id', $massDestroyRequest->input('indices'));
|
||||
|
||||
try {
|
||||
foreach ($activities as $activity) {
|
||||
Event::dispatch('activity.delete.before', $activity->id);
|
||||
|
||||
$this->activityRepository->delete($activity->id);
|
||||
|
||||
Event::dispatch('activity.delete.after', $activity->id);
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'message' => trans('admin::app.activities.mass-destroy-success'),
|
||||
]);
|
||||
} catch (\Exception $exception) {
|
||||
return response()->json([
|
||||
'message' => trans('admin::app.activities.mass-delete-failed'),
|
||||
], 400);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Admin\Http\Controllers\Configuration;
|
||||
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Support\Facades\Event;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\View\View;
|
||||
use Webkul\Admin\Http\Controllers\Controller;
|
||||
use Webkul\Admin\Http\Requests\ConfigurationForm;
|
||||
use Webkul\Core\Repositories\CoreConfigRepository as ConfigurationRepository;
|
||||
|
||||
class ConfigurationController extends Controller
|
||||
{
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(protected ConfigurationRepository $configurationRepository) {}
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*/
|
||||
public function index(): View
|
||||
{
|
||||
if (
|
||||
request()->route('slug')
|
||||
&& request()->route('slug2')
|
||||
) {
|
||||
return view('admin::configuration.edit');
|
||||
}
|
||||
|
||||
return view('admin::configuration.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*/
|
||||
public function store(ConfigurationForm $request): RedirectResponse
|
||||
{
|
||||
Event::dispatch('core.configuration.save.before');
|
||||
|
||||
$this->configurationRepository->create($request->all());
|
||||
|
||||
Event::dispatch('core.configuration.save.after');
|
||||
|
||||
session()->flash('success', trans('admin::app.configuration.index.save-success'));
|
||||
|
||||
return redirect()->back();
|
||||
}
|
||||
|
||||
/**
|
||||
* download the file for the specified resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function download()
|
||||
{
|
||||
$path = request()->route()->parameters()['path'];
|
||||
|
||||
$fileName = 'configuration/'.$path;
|
||||
|
||||
$config = $this->configurationRepository->findOneByField('value', $fileName);
|
||||
|
||||
return Storage::download($config['value']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for configurations.
|
||||
*/
|
||||
public function search(): JsonResponse
|
||||
{
|
||||
$results = $this->configurationRepository->search(
|
||||
system_config()->getItems(),
|
||||
request()->query('query')
|
||||
);
|
||||
|
||||
return new JsonResponse([
|
||||
'data' => $results,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Admin\Http\Controllers\Contact;
|
||||
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Support\Facades\Event;
|
||||
use Illuminate\View\View;
|
||||
use Webkul\Admin\DataGrids\Contact\OrganizationDataGrid;
|
||||
use Webkul\Admin\Http\Controllers\Controller;
|
||||
use Webkul\Admin\Http\Requests\AttributeForm;
|
||||
use Webkul\Admin\Http\Requests\MassDestroyRequest;
|
||||
use Webkul\Contact\Repositories\OrganizationRepository;
|
||||
|
||||
class OrganizationController extends Controller
|
||||
{
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(protected OrganizationRepository $organizationRepository)
|
||||
{
|
||||
request()->request->add(['entity_type' => 'organizations']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*/
|
||||
public function index(): View|JsonResponse
|
||||
{
|
||||
if (request()->ajax()) {
|
||||
return datagrid(OrganizationDataGrid::class)->process();
|
||||
}
|
||||
|
||||
return view('admin::contacts.organizations.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*/
|
||||
public function create(): View
|
||||
{
|
||||
return view('admin::contacts.organizations.create');
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*/
|
||||
public function store(AttributeForm $request): RedirectResponse
|
||||
{
|
||||
Event::dispatch('contacts.organization.create.before');
|
||||
|
||||
$organization = $this->organizationRepository->create(request()->all());
|
||||
|
||||
Event::dispatch('contacts.organization.create.after', $organization);
|
||||
|
||||
session()->flash('success', trans('admin::app.contacts.organizations.index.create-success'));
|
||||
|
||||
return redirect()->route('admin.contacts.organizations.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*/
|
||||
public function edit(int $id): View
|
||||
{
|
||||
$organization = $this->organizationRepository->findOrFail($id);
|
||||
|
||||
return view('admin::contacts.organizations.edit', compact('organization'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*/
|
||||
public function update(AttributeForm $request, int $id): RedirectResponse
|
||||
{
|
||||
Event::dispatch('contacts.organization.update.before', $id);
|
||||
|
||||
$organization = $this->organizationRepository->update(request()->all(), $id);
|
||||
|
||||
Event::dispatch('contacts.organization.update.after', $organization);
|
||||
|
||||
session()->flash('success', trans('admin::app.contacts.organizations.index.update-success'));
|
||||
|
||||
return redirect()->route('admin.contacts.organizations.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*/
|
||||
public function destroy(int $id): JsonResponse
|
||||
{
|
||||
try {
|
||||
Event::dispatch('contact.organization.delete.before', $id);
|
||||
|
||||
$this->organizationRepository->delete($id);
|
||||
|
||||
Event::dispatch('contact.organization.delete.after', $id);
|
||||
|
||||
return response()->json([
|
||||
'message' => trans('admin::app.contacts.organizations.index.delete-success'),
|
||||
], 200);
|
||||
} catch (\Exception $exception) {
|
||||
return response()->json([
|
||||
'message' => trans('admin::app.contacts.organizations.index.delete-failed'),
|
||||
], 400);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mass Delete the specified resources.
|
||||
*/
|
||||
public function massDestroy(MassDestroyRequest $massDestroyRequest): JsonResponse
|
||||
{
|
||||
$organizations = $this->organizationRepository->findWhereIn('id', $massDestroyRequest->input('indices'));
|
||||
|
||||
foreach ($organizations as $organization) {
|
||||
Event::dispatch('contact.organization.delete.before', $organization);
|
||||
|
||||
$this->organizationRepository->delete($organization->id);
|
||||
|
||||
Event::dispatch('contact.organization.delete.after', $organization);
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'message' => trans('admin::app.contacts.organizations.index.delete-success'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Admin\Http\Controllers\Contact\Persons;
|
||||
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Webkul\Activity\Repositories\ActivityRepository;
|
||||
use Webkul\Admin\Http\Controllers\Controller;
|
||||
use Webkul\Admin\Http\Resources\ActivityResource;
|
||||
use Webkul\Email\Repositories\AttachmentRepository;
|
||||
use Webkul\Email\Repositories\EmailRepository;
|
||||
|
||||
class ActivityController extends Controller
|
||||
{
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(
|
||||
protected ActivityRepository $activityRepository,
|
||||
protected EmailRepository $emailRepository,
|
||||
protected AttachmentRepository $attachmentRepository
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function index($id)
|
||||
{
|
||||
$activities = $this->activityRepository
|
||||
->leftJoin('person_activities', 'activities.id', '=', 'person_activities.activity_id')
|
||||
->where('person_activities.person_id', $id)
|
||||
->get();
|
||||
|
||||
return ActivityResource::collection($this->concatEmailAsActivities($id, $activities));
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*/
|
||||
public function concatEmailAsActivities($personId, $activities)
|
||||
{
|
||||
$emails = DB::table('emails as child')
|
||||
->select('child.*')
|
||||
->join('emails as parent', 'child.parent_id', '=', 'parent.id')
|
||||
->where('parent.person_id', $personId)
|
||||
->union(DB::table('emails as parent')->where('parent.person_id', $personId))
|
||||
->get();
|
||||
|
||||
return $activities->concat($emails->map(function ($email) {
|
||||
return (object) [
|
||||
'id' => $email->id,
|
||||
'parent_id' => $email->parent_id,
|
||||
'title' => $email->subject,
|
||||
'type' => 'email',
|
||||
'is_done' => 1,
|
||||
'comment' => $email->reply,
|
||||
'schedule_from' => null,
|
||||
'schedule_to' => null,
|
||||
'user' => auth()->guard('user')->user(),
|
||||
'participants' => [],
|
||||
'location' => null,
|
||||
'additional' => [
|
||||
'folders' => json_decode($email->folders),
|
||||
'from' => json_decode($email->from),
|
||||
'to' => json_decode($email->reply_to),
|
||||
'cc' => json_decode($email->cc),
|
||||
'bcc' => json_decode($email->bcc),
|
||||
],
|
||||
'files' => $this->attachmentRepository->findWhere(['email_id' => $email->id])->map(function ($attachment) {
|
||||
return (object) [
|
||||
'id' => $attachment->id,
|
||||
'name' => $attachment->name,
|
||||
'path' => $attachment->path,
|
||||
'url' => $attachment->url,
|
||||
'created_at' => $attachment->created_at,
|
||||
'updated_at' => $attachment->updated_at,
|
||||
];
|
||||
}),
|
||||
'created_at' => $email->created_at,
|
||||
'updated_at' => $email->updated_at,
|
||||
];
|
||||
}))->sortByDesc('id')->sortByDesc('created_at');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,235 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Admin\Http\Controllers\Contact\Persons;
|
||||
|
||||
use Exception;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
use Illuminate\Support\Facades\Event;
|
||||
use Illuminate\View\View;
|
||||
use Prettus\Repository\Criteria\RequestCriteria;
|
||||
use Webkul\Admin\DataGrids\Contact\PersonDataGrid;
|
||||
use Webkul\Admin\Http\Controllers\Controller;
|
||||
use Webkul\Admin\Http\Requests\AttributeForm;
|
||||
use Webkul\Admin\Http\Requests\MassDestroyRequest;
|
||||
use Webkul\Admin\Http\Resources\PersonResource;
|
||||
use Webkul\Contact\Repositories\PersonRepository;
|
||||
|
||||
class PersonController extends Controller
|
||||
{
|
||||
/**
|
||||
* Create a new class instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(protected PersonRepository $personRepository)
|
||||
{
|
||||
request()->request->add(['entity_type' => 'persons']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
if (request()->ajax()) {
|
||||
return datagrid(PersonDataGrid::class)->process();
|
||||
}
|
||||
|
||||
return view('admin::contacts.persons.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*/
|
||||
public function create(): View
|
||||
{
|
||||
return view('admin::contacts.persons.create');
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*/
|
||||
public function store(AttributeForm $request): RedirectResponse|JsonResponse
|
||||
{
|
||||
Event::dispatch('contacts.person.create.before');
|
||||
|
||||
$person = $this->personRepository->create($request->all());
|
||||
|
||||
Event::dispatch('contacts.person.create.after', $person);
|
||||
|
||||
if (request()->ajax()) {
|
||||
return response()->json([
|
||||
'data' => $person,
|
||||
'message' => trans('admin::app.contacts.persons.index.create-success'),
|
||||
]);
|
||||
}
|
||||
|
||||
session()->flash('success', trans('admin::app.contacts.persons.index.create-success'));
|
||||
|
||||
return redirect()->route('admin.contacts.persons.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the specified resource.
|
||||
*/
|
||||
public function show(int $id): View
|
||||
{
|
||||
$person = $this->personRepository->findOrFail($id);
|
||||
|
||||
return view('admin::contacts.persons.view', compact('person'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*/
|
||||
public function edit(int $id): View
|
||||
{
|
||||
$person = $this->personRepository->findOrFail($id);
|
||||
|
||||
return view('admin::contacts.persons.edit', compact('person'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*/
|
||||
public function update(AttributeForm $request, int $id): RedirectResponse|JsonResponse
|
||||
{
|
||||
Event::dispatch('contacts.person.update.before', $id);
|
||||
|
||||
$person = $this->personRepository->update($request->all(), $id);
|
||||
|
||||
Event::dispatch('contacts.person.update.after', $person);
|
||||
|
||||
if (request()->ajax()) {
|
||||
return response()->json([
|
||||
'data' => $person,
|
||||
'message' => trans('admin::app.contacts.persons.index.update-success'),
|
||||
], 200);
|
||||
}
|
||||
|
||||
session()->flash('success', trans('admin::app.contacts.persons.index.update-success'));
|
||||
|
||||
return redirect()->route('admin.contacts.persons.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Search person results.
|
||||
*/
|
||||
public function search(): JsonResource
|
||||
{
|
||||
if ($userIds = bouncer()->getAuthorizedUserIds()) {
|
||||
$persons = $this->personRepository
|
||||
->pushCriteria(app(RequestCriteria::class))
|
||||
->findWhereIn('user_id', $userIds);
|
||||
} else {
|
||||
$persons = $this->personRepository
|
||||
->pushCriteria(app(RequestCriteria::class))
|
||||
->all();
|
||||
}
|
||||
|
||||
return PersonResource::collection($persons);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*/
|
||||
public function destroy(int $id): JsonResponse
|
||||
{
|
||||
$person = $this->personRepository->findOrFail($id);
|
||||
|
||||
if (
|
||||
$person->leads
|
||||
&& $person->leads->count() > 0
|
||||
) {
|
||||
return response()->json([
|
||||
'message' => trans('admin::app.contacts.persons.index.delete-failed'),
|
||||
], 400);
|
||||
}
|
||||
|
||||
try {
|
||||
Event::dispatch('contacts.person.delete.before', $person);
|
||||
|
||||
$person->delete();
|
||||
|
||||
Event::dispatch('contacts.person.delete.after', $person);
|
||||
|
||||
return response()->json([
|
||||
'message' => trans('admin::app.contacts.persons.index.delete-success'),
|
||||
], 200);
|
||||
|
||||
} catch (Exception $exception) {
|
||||
return response()->json([
|
||||
'message' => trans('admin::app.contacts.persons.index.delete-failed'),
|
||||
], 400);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mass destroy the specified resources from storage.
|
||||
*/
|
||||
public function massDestroy(MassDestroyRequest $request): JsonResponse
|
||||
{
|
||||
try {
|
||||
$persons = $this->personRepository->findWhereIn('id', $request->input('indices', []));
|
||||
|
||||
$deletedCount = 0;
|
||||
|
||||
$blockedCount = 0;
|
||||
|
||||
foreach ($persons as $person) {
|
||||
if (
|
||||
$person->leads
|
||||
&& $person->leads->count() > 0
|
||||
) {
|
||||
$blockedCount++;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
Event::dispatch('contact.person.delete.before', $person);
|
||||
|
||||
$this->personRepository->delete($person->id);
|
||||
|
||||
Event::dispatch('contact.person.delete.after', $person);
|
||||
|
||||
$deletedCount++;
|
||||
}
|
||||
|
||||
$statusCode = 200;
|
||||
|
||||
switch (true) {
|
||||
case $deletedCount > 0 && $blockedCount === 0:
|
||||
$message = trans('admin::app.contacts.persons.index.all-delete-success');
|
||||
|
||||
break;
|
||||
|
||||
case $deletedCount > 0 && $blockedCount > 0:
|
||||
$message = trans('admin::app.contacts.persons.index.partial-delete-warning');
|
||||
|
||||
break;
|
||||
|
||||
case $deletedCount === 0 && $blockedCount > 0:
|
||||
$message = trans('admin::app.contacts.persons.index.none-delete-warning');
|
||||
|
||||
$statusCode = 400;
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
$message = trans('admin::app.contacts.persons.index.no-selection');
|
||||
|
||||
$statusCode = 400;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return response()->json(['message' => $message], $statusCode);
|
||||
} catch (Exception $exception) {
|
||||
return response()->json([
|
||||
'message' => trans('admin::app.contacts.persons.index.delete-failed'),
|
||||
], 400);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Admin\Http\Controllers\Contact\Persons;
|
||||
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Support\Facades\Event;
|
||||
use Webkul\Admin\Http\Controllers\Controller;
|
||||
use Webkul\Contact\Repositories\PersonRepository;
|
||||
|
||||
class TagController extends Controller
|
||||
{
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(protected PersonRepository $personRepository) {}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*/
|
||||
public function attach(int $id): JsonResponse
|
||||
{
|
||||
Event::dispatch('persons.tag.create.before', $id);
|
||||
|
||||
$person = $this->personRepository->find($id);
|
||||
|
||||
if (! $person->tags->contains(request()->input('tag_id'))) {
|
||||
$person->tags()->attach(request()->input('tag_id'));
|
||||
}
|
||||
|
||||
Event::dispatch('persons.tag.create.after', $person);
|
||||
|
||||
return response()->json([
|
||||
'message' => trans('admin::app.contacts.persons.view.tags.create-success'),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*/
|
||||
public function detach(int $personId): JsonResponse
|
||||
{
|
||||
Event::dispatch('persons.tag.delete.before', $personId);
|
||||
|
||||
$person = $this->personRepository->find($personId);
|
||||
|
||||
$person->tags()->detach(request()->input('tag_id'));
|
||||
|
||||
Event::dispatch('persons.tag.delete.after', $person);
|
||||
|
||||
return response()->json([
|
||||
'message' => trans('admin::app.contacts.persons.view.tags.destroy-success'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
23
packages/Webkul/Admin/src/Http/Controllers/Controller.php
Executable file
23
packages/Webkul/Admin/src/Http/Controllers/Controller.php
Executable file
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Admin\Http\Controllers;
|
||||
|
||||
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
|
||||
use Illuminate\Foundation\Bus\DispatchesJobs;
|
||||
use Illuminate\Foundation\Validation\ValidatesRequests;
|
||||
use Illuminate\Routing\Controller as BaseController;
|
||||
|
||||
class Controller extends BaseController
|
||||
{
|
||||
use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function redirectToLogin()
|
||||
{
|
||||
return redirect()->route('admin.session.create');
|
||||
}
|
||||
}
|
||||
59
packages/Webkul/Admin/src/Http/Controllers/DashboardController.php
Executable file
59
packages/Webkul/Admin/src/Http/Controllers/DashboardController.php
Executable file
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Admin\Http\Controllers;
|
||||
|
||||
use Webkul\Admin\Helpers\Dashboard;
|
||||
|
||||
class DashboardController extends Controller
|
||||
{
|
||||
/**
|
||||
* Request param functions
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $typeFunctions = [
|
||||
'over-all' => 'getOverAllStats',
|
||||
'revenue-stats' => 'getRevenueStats',
|
||||
'total-leads' => 'getTotalLeadsStats',
|
||||
'revenue-by-sources' => 'getLeadsStatsBySources',
|
||||
'revenue-by-types' => 'getLeadsStatsByTypes',
|
||||
'top-selling-products' => 'getTopSellingProducts',
|
||||
'top-persons' => 'getTopPersons',
|
||||
'open-leads-by-states' => 'getOpenLeadsByStates',
|
||||
];
|
||||
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(protected Dashboard $dashboardHelper) {}
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
return view('admin::dashboard.index')->with([
|
||||
'startDate' => $this->dashboardHelper->getStartDate(),
|
||||
'endDate' => $this->dashboardHelper->getEndDate(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function stats()
|
||||
{
|
||||
$stats = $this->dashboardHelper->{$this->typeFunctions[request()->query('type')]}();
|
||||
|
||||
return response()->json([
|
||||
'statistics' => $stats,
|
||||
'date_range' => $this->dashboardHelper->getDateRange(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Admin\Http\Controllers\DataGrid;
|
||||
|
||||
use Illuminate\Support\Facades\Event;
|
||||
use Webkul\Admin\Http\Controllers\Controller;
|
||||
use Webkul\DataGrid\Repositories\SavedFilterRepository;
|
||||
|
||||
class SavedFilterController extends Controller
|
||||
{
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
*/
|
||||
public function __construct(protected SavedFilterRepository $savedFilterRepository) {}
|
||||
|
||||
/**
|
||||
* Save filters to the database.
|
||||
*/
|
||||
public function store()
|
||||
{
|
||||
$userId = auth()->guard()->user()->id;
|
||||
|
||||
$this->validate(request(), [
|
||||
'name' => 'required|unique:datagrid_saved_filters,name,NULL,id,src,'.request('src').',user_id,'.$userId,
|
||||
]);
|
||||
|
||||
Event::dispatch('datagrid.saved_filter.create.before');
|
||||
|
||||
$savedFilter = $this->savedFilterRepository->create([
|
||||
'user_id' => $userId,
|
||||
'name' => request('name'),
|
||||
'src' => request('src'),
|
||||
'applied' => request('applied'),
|
||||
]);
|
||||
|
||||
Event::dispatch('datagrid.saved_filter.create.after', $savedFilter);
|
||||
|
||||
return response()->json([
|
||||
'data' => $savedFilter,
|
||||
'message' => trans('admin::app.components.datagrid.toolbar.filter.saved-success'),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the saved filters.
|
||||
*/
|
||||
public function get()
|
||||
{
|
||||
$savedFilters = $this->savedFilterRepository->findWhere([
|
||||
'src' => request()->get('src'),
|
||||
'user_id' => auth()->guard()->user()->id,
|
||||
]);
|
||||
|
||||
return response()->json(['data' => $savedFilters]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the saved filter.
|
||||
*/
|
||||
public function update(int $id)
|
||||
{
|
||||
$userId = auth()->guard()->user()->id;
|
||||
|
||||
$this->validate(request(), [
|
||||
'name' => 'required|unique:datagrid_saved_filters,name,'.$id.',id,src,'.request('src').',user_id,'.$userId,
|
||||
]);
|
||||
|
||||
$savedFilter = $this->savedFilterRepository->findOneWhere([
|
||||
'id' => $id,
|
||||
'user_id' => auth()->guard()->user()->id,
|
||||
]);
|
||||
|
||||
if (! $savedFilter) {
|
||||
return response()->json([], 404);
|
||||
}
|
||||
|
||||
Event::dispatch('datagrid.saved_filter.update.before', $id);
|
||||
|
||||
$updatedFilter = $this->savedFilterRepository->update(request()->only([
|
||||
'name',
|
||||
'src',
|
||||
'applied',
|
||||
]), $id);
|
||||
|
||||
Event::dispatch('datagrid.saved_filter.update.after', $updatedFilter);
|
||||
|
||||
return response()->json([
|
||||
'data' => $updatedFilter,
|
||||
'message' => trans('admin::app.components.datagrid.toolbar.filter.updated-success'),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the saved filter.
|
||||
*/
|
||||
public function destroy(int $id)
|
||||
{
|
||||
Event::dispatch('datagrid.saved_filter.delete.before', $id);
|
||||
|
||||
$success = $this->savedFilterRepository->deleteWhere([
|
||||
'id' => $id,
|
||||
'user_id' => auth()->guard()->user()->id,
|
||||
]);
|
||||
|
||||
Event::dispatch('datagrid.saved_filter.delete.after', $id);
|
||||
|
||||
if (! $success) {
|
||||
return response()->json([
|
||||
'message' => trans('admin::app.components.datagrid.toolbar.filter.delete-error'),
|
||||
]);
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'message' => trans('admin::app.components.datagrid.toolbar.filter.delete-success'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Admin\Http\Controllers;
|
||||
|
||||
use Illuminate\Support\Facades\Crypt;
|
||||
|
||||
class DataGridController extends Controller
|
||||
{
|
||||
/**
|
||||
* Look up.
|
||||
*/
|
||||
public function lookUp()
|
||||
{
|
||||
/**
|
||||
* Validation for parameters.
|
||||
*/
|
||||
$params = $this->validate(request(), [
|
||||
'datagrid_id' => ['required'],
|
||||
'column' => ['required'],
|
||||
'search' => ['required', 'min:2'],
|
||||
]);
|
||||
|
||||
/**
|
||||
* Preparing the datagrid instance and only columns.
|
||||
*/
|
||||
$datagrid = app(Crypt::decryptString($params['datagrid_id']));
|
||||
$datagrid->prepareColumns();
|
||||
|
||||
/**
|
||||
* Finding the first column from the collection.
|
||||
*/
|
||||
$column = collect($datagrid->getColumns())->map(fn ($column) => $column->toArray())->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();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Admin\Http\Controllers\Lead;
|
||||
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Webkul\Activity\Repositories\ActivityRepository;
|
||||
use Webkul\Admin\Http\Controllers\Controller;
|
||||
use Webkul\Admin\Http\Resources\ActivityResource;
|
||||
use Webkul\Email\Repositories\AttachmentRepository;
|
||||
use Webkul\Email\Repositories\EmailRepository;
|
||||
|
||||
class ActivityController extends Controller
|
||||
{
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(
|
||||
protected ActivityRepository $activityRepository,
|
||||
protected EmailRepository $emailRepository,
|
||||
protected AttachmentRepository $attachmentRepository
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function index($id)
|
||||
{
|
||||
$activities = $this->activityRepository
|
||||
->leftJoin('lead_activities', 'activities.id', '=', 'lead_activities.activity_id')
|
||||
->where('lead_activities.lead_id', $id)
|
||||
->get();
|
||||
|
||||
return ActivityResource::collection($this->concatEmailAsActivities($id, $activities));
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*/
|
||||
public function concatEmailAsActivities($leadId, $activities)
|
||||
{
|
||||
$emails = DB::table('emails as child')
|
||||
->select('child.*')
|
||||
->join('emails as parent', 'child.parent_id', '=', 'parent.id')
|
||||
->where('parent.lead_id', $leadId)
|
||||
->union(DB::table('emails as parent')->where('parent.lead_id', $leadId))
|
||||
->get();
|
||||
|
||||
return $activities->concat($emails->map(function ($email) {
|
||||
return (object) [
|
||||
'id' => $email->id,
|
||||
'parent_id' => $email->parent_id,
|
||||
'title' => $email->subject,
|
||||
'type' => 'email',
|
||||
'is_done' => 1,
|
||||
'comment' => $email->reply,
|
||||
'schedule_from' => null,
|
||||
'schedule_to' => null,
|
||||
'user' => auth()->guard('user')->user(),
|
||||
'participants' => [],
|
||||
'location' => null,
|
||||
'additional' => [
|
||||
'folders' => json_decode($email->folders),
|
||||
'from' => json_decode($email->from),
|
||||
'to' => json_decode($email->reply_to),
|
||||
'cc' => json_decode($email->cc),
|
||||
'bcc' => json_decode($email->bcc),
|
||||
],
|
||||
'files' => $this->attachmentRepository->findWhere(['email_id' => $email->id])->map(function ($attachment) {
|
||||
return (object) [
|
||||
'id' => $attachment->id,
|
||||
'name' => $attachment->name,
|
||||
'path' => $attachment->path,
|
||||
'url' => $attachment->url,
|
||||
'created_at' => $attachment->created_at,
|
||||
'updated_at' => $attachment->updated_at,
|
||||
];
|
||||
}),
|
||||
'created_at' => $email->created_at,
|
||||
'updated_at' => $email->updated_at,
|
||||
];
|
||||
}))->sortByDesc('id')->sortByDesc('created_at');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Admin\Http\Controllers\Lead;
|
||||
|
||||
use Illuminate\Support\Facades\Event;
|
||||
use Webkul\Admin\Http\Controllers\Mail\EmailController as BaseEmailController;
|
||||
use Webkul\Admin\Http\Resources\ActivityResource;
|
||||
|
||||
class EmailController extends BaseEmailController
|
||||
{
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function store()
|
||||
{
|
||||
$response = json_decode(parent::store()->getContent(), true);
|
||||
|
||||
return response()->json([
|
||||
'data' => $this->transformToActivity($response['data']),
|
||||
'message' => $response['message'],
|
||||
]);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function detach($id)
|
||||
{
|
||||
Event::dispatch('email.update.before', request()->input('email_id'));
|
||||
|
||||
$email = $this->emailRepository->update([
|
||||
'lead_id' => null,
|
||||
], request()->input('email_id'));
|
||||
|
||||
Event::dispatch('email.update.after', $email);
|
||||
|
||||
return response()->json([
|
||||
'message' => trans('admin::app.mail.update-success'),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform the email data to activity resource.
|
||||
*
|
||||
* @param array $data
|
||||
* @return \Webkul\Admin\Http\Resources\ActivityResource
|
||||
*/
|
||||
public function transformToActivity($data)
|
||||
{
|
||||
return new ActivityResource((object) [
|
||||
'id' => $data['id'],
|
||||
'parent_id' => $data['parent_id'],
|
||||
'title' => $data['subject'],
|
||||
'type' => 'email',
|
||||
'is_done' => 1,
|
||||
'comment' => $data['reply'],
|
||||
'schedule_from' => null,
|
||||
'schedule_to' => null,
|
||||
'user' => auth()->guard('user')->user(),
|
||||
'participants' => [],
|
||||
'location' => null,
|
||||
'additional' => json_encode([
|
||||
'folders' => $data['folders'],
|
||||
'from' => $data['from'],
|
||||
'to' => $data['reply_to'],
|
||||
'cc' => $data['cc'],
|
||||
'bcc' => $data['bcc'],
|
||||
]),
|
||||
'files' => array_map(function ($attachment) {
|
||||
return (object) $attachment;
|
||||
}, $data['attachments']),
|
||||
'created_at' => $data['created_at'],
|
||||
'updated_at' => $data['updated_at'],
|
||||
]);
|
||||
}
|
||||
}
|
||||
734
packages/Webkul/Admin/src/Http/Controllers/Lead/LeadController.php
Executable file
734
packages/Webkul/Admin/src/Http/Controllers/Lead/LeadController.php
Executable file
@@ -0,0 +1,734 @@
|
||||
<?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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Admin\Http\Controllers\Lead;
|
||||
|
||||
use Illuminate\Support\Facades\Event;
|
||||
use Webkul\Admin\Http\Controllers\Controller;
|
||||
use Webkul\Lead\Repositories\LeadRepository;
|
||||
use Webkul\Quote\Repositories\QuoteRepository;
|
||||
|
||||
class QuoteController extends Controller
|
||||
{
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(
|
||||
protected LeadRepository $leadRepository,
|
||||
protected QuoteRepository $quoteRepository
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function store($id)
|
||||
{
|
||||
Event::dispatch('leads.quote.create.before');
|
||||
|
||||
$lead = $this->leadRepository->find($id);
|
||||
|
||||
if (! $lead->quotes->contains(request('id'))) {
|
||||
$lead->quotes()->attach(request('id'));
|
||||
}
|
||||
|
||||
Event::dispatch('leads.quote.create.after', $lead);
|
||||
|
||||
return response()->json([
|
||||
'message' => trans('admin::app.leads.quote-create-success'),
|
||||
], 200);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @param int $leadId
|
||||
* @param int $tagId
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function delete($leadId)
|
||||
{
|
||||
Event::dispatch('leads.quote.delete.before', $leadId);
|
||||
|
||||
$lead = $this->leadRepository->find($leadId);
|
||||
|
||||
$lead->quotes()->detach(request('quote_id'));
|
||||
|
||||
Event::dispatch('leads.quote.delete.after', $lead);
|
||||
|
||||
return response()->json([
|
||||
'message' => trans('admin::app.leads.view.quotes.destroy-success'),
|
||||
], 200);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Admin\Http\Controllers\Lead;
|
||||
|
||||
use Illuminate\Support\Facades\Event;
|
||||
use Webkul\Admin\Http\Controllers\Controller;
|
||||
use Webkul\Lead\Repositories\LeadRepository;
|
||||
|
||||
class TagController extends Controller
|
||||
{
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(protected LeadRepository $leadRepository) {}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function attach($id)
|
||||
{
|
||||
Event::dispatch('leads.tag.create.before', $id);
|
||||
|
||||
$lead = $this->leadRepository->find($id);
|
||||
|
||||
if (! $lead->tags->contains(request()->input('tag_id'))) {
|
||||
$lead->tags()->attach(request()->input('tag_id'));
|
||||
}
|
||||
|
||||
Event::dispatch('leads.tag.create.after', $lead);
|
||||
|
||||
return response()->json([
|
||||
'message' => trans('admin::app.leads.view.tags.create-success'),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @param int $leadId
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function detach($leadId)
|
||||
{
|
||||
Event::dispatch('leads.tag.delete.before', $leadId);
|
||||
|
||||
$lead = $this->leadRepository->find($leadId);
|
||||
|
||||
$lead->tags()->detach(request()->input('tag_id'));
|
||||
|
||||
Event::dispatch('leads.tag.delete.after', $lead);
|
||||
|
||||
return response()->json([
|
||||
'message' => trans('admin::app.leads.view.tags.destroy-success'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,336 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Admin\Http\Controllers\Mail;
|
||||
|
||||
use Exception;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Support\Facades\Event;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\View\View;
|
||||
use Webkul\Admin\DataGrids\Mail\EmailDataGrid;
|
||||
use Webkul\Admin\Http\Controllers\Controller;
|
||||
use Webkul\Admin\Http\Requests\MassDestroyRequest;
|
||||
use Webkul\Admin\Http\Requests\MassUpdateRequest;
|
||||
use Webkul\Admin\Http\Resources\EmailResource;
|
||||
use Webkul\Email\InboundEmailProcessor\Contracts\InboundEmailProcessor;
|
||||
use Webkul\Email\Mails\Email;
|
||||
use Webkul\Email\Repositories\AttachmentRepository;
|
||||
use Webkul\Email\Repositories\EmailRepository;
|
||||
use Webkul\Lead\Repositories\LeadRepository;
|
||||
|
||||
class EmailController extends Controller
|
||||
{
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(
|
||||
protected LeadRepository $leadRepository,
|
||||
protected EmailRepository $emailRepository,
|
||||
protected AttachmentRepository $attachmentRepository
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*/
|
||||
public function index(): View|JsonResponse|RedirectResponse
|
||||
{
|
||||
if (! request('route')) {
|
||||
return redirect()->route('admin.mail.index', ['route' => 'inbox']);
|
||||
}
|
||||
|
||||
if (! bouncer()->hasPermission('mail.'.request('route'))) {
|
||||
abort(401, 'This action is unauthorized');
|
||||
}
|
||||
|
||||
switch (request('route')) {
|
||||
case 'compose':
|
||||
return view('admin::mail.compose');
|
||||
|
||||
default:
|
||||
if (request()->ajax()) {
|
||||
return datagrid(EmailDataGrid::class)->process();
|
||||
}
|
||||
|
||||
return view('admin::mail.index');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a resource.
|
||||
*
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function view()
|
||||
{
|
||||
$email = $this->emailRepository
|
||||
->with(['emails', 'attachments', 'emails.attachments', 'lead', 'lead.person', 'lead.tags', 'lead.source', 'lead.type', 'person'])
|
||||
->findOrFail(request('id'));
|
||||
|
||||
if ($userIds = bouncer()->getAuthorizedUserIds()) {
|
||||
$results = $this->leadRepository->findWhere([
|
||||
['id', '=', $email->lead_id],
|
||||
['user_id', 'IN', $userIds],
|
||||
]);
|
||||
} else {
|
||||
$results = $this->leadRepository->findWhere([
|
||||
['id', '=', $email->lead_id],
|
||||
]);
|
||||
}
|
||||
|
||||
if (empty($results->toArray())) {
|
||||
unset($email->lead_id);
|
||||
}
|
||||
|
||||
if (request('route') == 'draft') {
|
||||
return response()->json([
|
||||
'data' => new EmailResource($email),
|
||||
]);
|
||||
}
|
||||
|
||||
return view('admin::mail.view', compact('email'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function store()
|
||||
{
|
||||
$this->validate(request(), [
|
||||
'reply_to' => 'required|array|min:1',
|
||||
'reply_to.*' => 'email',
|
||||
'reply' => 'required',
|
||||
]);
|
||||
|
||||
Event::dispatch('email.create.before');
|
||||
|
||||
$email = $this->emailRepository->create(request()->all());
|
||||
|
||||
if (! request('is_draft')) {
|
||||
try {
|
||||
Mail::send(new Email($email));
|
||||
|
||||
$this->emailRepository->update([
|
||||
'folders' => ['sent'],
|
||||
], $email->id);
|
||||
} catch (\Exception $e) {
|
||||
}
|
||||
}
|
||||
|
||||
Event::dispatch('email.create.after', $email);
|
||||
|
||||
if (request()->ajax()) {
|
||||
return response()->json([
|
||||
'data' => new EmailResource($email),
|
||||
'message' => trans('admin::app.mail.create-success'),
|
||||
]);
|
||||
}
|
||||
|
||||
if (request('is_draft')) {
|
||||
session()->flash('success', trans('admin::app.mail.saved-to-draft'));
|
||||
|
||||
return redirect()->route('admin.mail.index', ['route' => 'draft']);
|
||||
}
|
||||
|
||||
session()->flash('success', trans('admin::app.mail.create-success'));
|
||||
|
||||
return redirect()->route('admin.mail.index', ['route' => 'sent']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function update($id)
|
||||
{
|
||||
Event::dispatch('email.update.before', $id);
|
||||
|
||||
$data = request()->all();
|
||||
|
||||
if (! is_null(request('is_draft'))) {
|
||||
$data['folders'] = request('is_draft') ? ['draft'] : ['outbox'];
|
||||
}
|
||||
|
||||
$email = $this->emailRepository->update($data, request('id') ?? $id);
|
||||
|
||||
Event::dispatch('email.update.after', $email);
|
||||
|
||||
if (! is_null(request('is_draft')) && ! request('is_draft')) {
|
||||
try {
|
||||
Mail::send(new Email($email));
|
||||
|
||||
$this->emailRepository->update([
|
||||
'folders' => ['inbox', 'sent'],
|
||||
], $email->id);
|
||||
} catch (\Exception $e) {
|
||||
}
|
||||
}
|
||||
|
||||
if (! is_null(request('is_draft'))) {
|
||||
if (request('is_draft')) {
|
||||
session()->flash('success', trans('admin::app.mail.saved-to-draft'));
|
||||
|
||||
return redirect()->route('admin.mail.index', ['route' => 'draft']);
|
||||
} else {
|
||||
session()->flash('success', trans('admin::app.mail.create-success'));
|
||||
|
||||
return redirect()->route('admin.mail.index', ['route' => 'inbox']);
|
||||
}
|
||||
}
|
||||
|
||||
if (request()->ajax()) {
|
||||
return response()->json([
|
||||
'data' => new EmailResource($email->refresh()),
|
||||
'message' => trans('admin::app.mail.update-success'),
|
||||
]);
|
||||
}
|
||||
|
||||
session()->flash('success', trans('admin::app.mail.update-success'));
|
||||
|
||||
return redirect()->back();
|
||||
}
|
||||
|
||||
/**
|
||||
* Run process inbound parse email.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function inboundParse(InboundEmailProcessor $inboundEmailProcessor)
|
||||
{
|
||||
$inboundEmailProcessor->processMessage(request('email'));
|
||||
|
||||
return response()->json([], 200);
|
||||
}
|
||||
|
||||
/**
|
||||
* Download file from storage
|
||||
*
|
||||
* @param int $id
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function download($id)
|
||||
{
|
||||
$attachment = $this->attachmentRepository->findOrFail($id);
|
||||
|
||||
try {
|
||||
return Storage::download($attachment->path);
|
||||
} catch (\Exception $e) {
|
||||
session()->flash('error', $e->getMessage());
|
||||
|
||||
return redirect()->back();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mass Update the specified resources.
|
||||
*/
|
||||
public function massUpdate(MassUpdateRequest $massUpdateRequest): JsonResponse
|
||||
{
|
||||
$emails = $this->emailRepository->findWhereIn('id', $massUpdateRequest->input('indices'));
|
||||
|
||||
try {
|
||||
foreach ($emails as $email) {
|
||||
Event::dispatch('email.update.before', $email->id);
|
||||
|
||||
$this->emailRepository->update([
|
||||
'folders' => request('folders'),
|
||||
], $email->id);
|
||||
|
||||
Event::dispatch('email.update.after', $email->id);
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'message' => trans('admin::app.mail.mass-update-success'),
|
||||
]);
|
||||
} catch (Exception) {
|
||||
return response()->json([
|
||||
'message' => trans('admin::app.mail.mass-update-success'),
|
||||
], 400);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*/
|
||||
public function destroy(int $id): JsonResponse|RedirectResponse
|
||||
{
|
||||
$email = $this->emailRepository->findOrFail($id);
|
||||
|
||||
try {
|
||||
Event::dispatch('email.'.request('type').'.before', $id);
|
||||
|
||||
$parentId = $email->parent_id;
|
||||
|
||||
if (request('type') == 'trash') {
|
||||
$this->emailRepository->update([
|
||||
'folders' => ['trash'],
|
||||
], $id);
|
||||
} else {
|
||||
$this->emailRepository->delete($id);
|
||||
}
|
||||
|
||||
Event::dispatch('email.'.request('type').'.after', $id);
|
||||
|
||||
if (request()->ajax()) {
|
||||
return response()->json([
|
||||
'message' => trans('admin::app.mail.delete-success'),
|
||||
], 200);
|
||||
}
|
||||
|
||||
session()->flash('success', trans('admin::app.mail.delete-success'));
|
||||
|
||||
if ($parentId) {
|
||||
return redirect()->back();
|
||||
}
|
||||
|
||||
return redirect()->route('admin.mail.index', ['route' => 'inbox']);
|
||||
} catch (\Exception $exception) {
|
||||
if (request()->ajax()) {
|
||||
return response()->json([
|
||||
'message' => trans('admin::app.mail.delete-failed'),
|
||||
], 400);
|
||||
}
|
||||
|
||||
session()->flash('error', trans('admin::app.mail.delete-failed'));
|
||||
|
||||
return redirect()->back();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mass Delete the specified resources.
|
||||
*/
|
||||
public function massDestroy(MassDestroyRequest $massDestroyRequest): JsonResponse
|
||||
{
|
||||
$mails = $this->emailRepository->findWhereIn('id', $massDestroyRequest->input('indices'));
|
||||
|
||||
try {
|
||||
foreach ($mails as $email) {
|
||||
Event::dispatch('email.'.$massDestroyRequest->input('type').'.before', $email->id);
|
||||
|
||||
if ($massDestroyRequest->input('type') == 'trash') {
|
||||
$this->emailRepository->update(['folders' => ['trash']], $email->id);
|
||||
} else {
|
||||
$this->emailRepository->delete($email->id);
|
||||
}
|
||||
|
||||
Event::dispatch('email.'.$massDestroyRequest->input('type').'.after', $email->id);
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'message' => trans('admin::app.mail.delete-success'),
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
return response()->json([
|
||||
'message' => trans('admin::app.mail.delete-success'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Admin\Http\Controllers\Mail;
|
||||
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Support\Facades\Event;
|
||||
use Webkul\Admin\Http\Controllers\Controller;
|
||||
use Webkul\Email\Repositories\EmailRepository;
|
||||
|
||||
class TagController extends Controller
|
||||
{
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(protected EmailRepository $emailRepository) {}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*/
|
||||
public function attach(int $id): JsonResponse
|
||||
{
|
||||
Event::dispatch('mails.tag.create.before', $id);
|
||||
|
||||
$mail = $this->emailRepository->find($id);
|
||||
|
||||
if (! $mail->tags->contains(request()->input('tag_id'))) {
|
||||
$mail->tags()->attach(request()->input('tag_id'));
|
||||
}
|
||||
|
||||
Event::dispatch('mails.tag.create.after', $mail);
|
||||
|
||||
return response()->json([
|
||||
'message' => trans('admin::app.mail.view.tags.create-success'),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*/
|
||||
public function detach(int $mailId): JsonResponse
|
||||
{
|
||||
Event::dispatch('mails.tag.delete.before', $mailId);
|
||||
|
||||
$mail = $this->emailRepository->find($mailId);
|
||||
|
||||
$mail->tags()->detach(request()->input('tag_id'));
|
||||
|
||||
Event::dispatch('mails.tag.delete.after', $mail);
|
||||
|
||||
return response()->json([
|
||||
'message' => trans('admin::app.mail.view.tags.destroy-success'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Admin\Http\Controllers\Products;
|
||||
|
||||
use Webkul\Activity\Repositories\ActivityRepository;
|
||||
use Webkul\Admin\Http\Controllers\Controller;
|
||||
use Webkul\Admin\Http\Resources\ActivityResource;
|
||||
use Webkul\Email\Repositories\EmailRepository;
|
||||
|
||||
class ActivityController extends Controller
|
||||
{
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(
|
||||
protected ActivityRepository $activityRepository,
|
||||
protected EmailRepository $emailRepository
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function index($id)
|
||||
{
|
||||
$activities = $this->activityRepository
|
||||
->leftJoin('product_activities', 'activities.id', '=', 'product_activities.activity_id')
|
||||
->where('product_activities.product_id', $id)
|
||||
->get();
|
||||
|
||||
return ActivityResource::collection($this->concatEmail($activities));
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*/
|
||||
public function concatEmail($activities)
|
||||
{
|
||||
return $activities->sortByDesc('id')->sortByDesc('created_at');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,216 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Admin\Http\Controllers\Products;
|
||||
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
use Illuminate\Support\Facades\Event;
|
||||
use Illuminate\View\View;
|
||||
use Prettus\Repository\Criteria\RequestCriteria;
|
||||
use Webkul\Admin\DataGrids\Product\ProductDataGrid;
|
||||
use Webkul\Admin\Http\Controllers\Controller;
|
||||
use Webkul\Admin\Http\Requests\AttributeForm;
|
||||
use Webkul\Admin\Http\Requests\MassDestroyRequest;
|
||||
use Webkul\Admin\Http\Resources\ProductResource;
|
||||
use Webkul\Product\Repositories\ProductRepository;
|
||||
|
||||
class ProductController extends Controller
|
||||
{
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(protected ProductRepository $productRepository)
|
||||
{
|
||||
request()->request->add(['entity_type' => 'products']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*/
|
||||
public function index(): View|JsonResponse
|
||||
{
|
||||
if (request()->ajax()) {
|
||||
return datagrid(ProductDataGrid::class)->process();
|
||||
}
|
||||
|
||||
return view('admin::products.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*/
|
||||
public function create(): View
|
||||
{
|
||||
return view('admin::products.create');
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function store(AttributeForm $request)
|
||||
{
|
||||
Event::dispatch('product.create.before');
|
||||
|
||||
$product = $this->productRepository->create($request->all());
|
||||
|
||||
Event::dispatch('product.create.after', $product);
|
||||
|
||||
session()->flash('success', trans('admin::app.products.index.create-success'));
|
||||
|
||||
return redirect()->route('admin.products.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for viewing the specified resource.
|
||||
*/
|
||||
public function view(int $id): View
|
||||
{
|
||||
$product = $this->productRepository->findOrFail($id);
|
||||
|
||||
return view('admin::products.view', compact('product'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*/
|
||||
public function edit(int $id): View|JsonResponse
|
||||
{
|
||||
$product = $this->productRepository->findOrFail($id);
|
||||
|
||||
$inventories = $product->inventories()
|
||||
->with('location')
|
||||
->get()
|
||||
->map(function ($inventory) {
|
||||
return [
|
||||
'id' => $inventory->id,
|
||||
'name' => $inventory->location->name,
|
||||
'warehouse_id' => $inventory->warehouse_id,
|
||||
'warehouse_location_id' => $inventory->warehouse_location_id,
|
||||
'in_stock' => $inventory->in_stock,
|
||||
'allocated' => $inventory->allocated,
|
||||
];
|
||||
});
|
||||
|
||||
return view('admin::products.edit', compact('product', 'inventories'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*/
|
||||
public function update(AttributeForm $request, int $id)
|
||||
{
|
||||
Event::dispatch('product.update.before', $id);
|
||||
|
||||
$product = $this->productRepository->update($request->all(), $id);
|
||||
|
||||
Event::dispatch('product.update.after', $product);
|
||||
|
||||
if (request()->ajax()) {
|
||||
return response()->json([
|
||||
'message' => trans('admin::app.products.index.update-success'),
|
||||
]);
|
||||
}
|
||||
|
||||
session()->flash('success', trans('admin::app.products.index.update-success'));
|
||||
|
||||
return redirect()->route('admin.products.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*/
|
||||
public function storeInventories(int $id, ?int $warehouseId = null): JsonResponse
|
||||
{
|
||||
$this->validate(request(), [
|
||||
'inventories' => 'array',
|
||||
'inventories.*.warehouse_location_id' => 'required',
|
||||
'inventories.*.warehouse_id' => 'required',
|
||||
'inventories.*.in_stock' => 'required|integer|min:0',
|
||||
'inventories.*.allocated' => 'required|integer|min:0',
|
||||
]);
|
||||
|
||||
$product = $this->productRepository->findOrFail($id);
|
||||
|
||||
Event::dispatch('product.update.before', $id);
|
||||
|
||||
$this->productRepository->saveInventories(request()->all(), $id, $warehouseId);
|
||||
|
||||
Event::dispatch('product.update.after', $product);
|
||||
|
||||
return new JsonResponse([
|
||||
'message' => trans('admin::app.products.index.update-success'),
|
||||
], 200);
|
||||
}
|
||||
|
||||
/**
|
||||
* Search product results
|
||||
*/
|
||||
public function search(): JsonResource
|
||||
{
|
||||
$products = $this->productRepository
|
||||
->pushCriteria(app(RequestCriteria::class))
|
||||
->orderBy('created_at', 'desc')
|
||||
->take(5)
|
||||
->get();
|
||||
|
||||
return ProductResource::collection($products);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns product inventories grouped by warehouse.
|
||||
*/
|
||||
public function warehouses(int $id): JsonResponse
|
||||
{
|
||||
$warehouses = $this->productRepository->getInventoriesGroupedByWarehouse($id);
|
||||
|
||||
return response()->json(array_values($warehouses));
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*/
|
||||
public function destroy(int $id): JsonResponse
|
||||
{
|
||||
$product = $this->productRepository->findOrFail($id);
|
||||
|
||||
try {
|
||||
Event::dispatch('settings.products.delete.before', $id);
|
||||
|
||||
$product->delete($id);
|
||||
|
||||
Event::dispatch('settings.products.delete.after', $id);
|
||||
|
||||
return new JsonResponse([
|
||||
'message' => trans('admin::app.products.index.delete-success'),
|
||||
], 200);
|
||||
} catch (\Exception $exception) {
|
||||
return new JsonResponse([
|
||||
'message' => trans('admin::app.products.index.delete-failed'),
|
||||
], 400);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mass Delete the specified resources.
|
||||
*/
|
||||
public function massDestroy(MassDestroyRequest $massDestroyRequest): JsonResponse
|
||||
{
|
||||
$indices = $massDestroyRequest->input('indices');
|
||||
|
||||
foreach ($indices as $index) {
|
||||
Event::dispatch('product.delete.before', $index);
|
||||
|
||||
$this->productRepository->delete($index);
|
||||
|
||||
Event::dispatch('product.delete.after', $index);
|
||||
}
|
||||
|
||||
return new JsonResponse([
|
||||
'message' => trans('admin::app.products.index.delete-success'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Admin\Http\Controllers\Products;
|
||||
|
||||
use Illuminate\Support\Facades\Event;
|
||||
use Webkul\Admin\Http\Controllers\Controller;
|
||||
use Webkul\Product\Repositories\ProductRepository;
|
||||
|
||||
class TagController extends Controller
|
||||
{
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(protected ProductRepository $productRepository) {}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*
|
||||
* @param int $id
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function attach($id)
|
||||
{
|
||||
Event::dispatch('products.tag.create.before', $id);
|
||||
|
||||
$product = $this->productRepository->findOrFail($id);
|
||||
|
||||
if (! $product->tags->contains(request()->input('tag_id'))) {
|
||||
$product->tags()->attach(request()->input('tag_id'));
|
||||
}
|
||||
|
||||
Event::dispatch('products.tag.create.after', $product);
|
||||
|
||||
return response()->json([
|
||||
'message' => trans('admin::app.leads.view.tags.create-success'),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @param int $productId
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function detach($productId)
|
||||
{
|
||||
Event::dispatch('products.tag.delete.before', $productId);
|
||||
|
||||
$product = $this->productRepository->find($productId);
|
||||
|
||||
$product->tags()->detach(request()->input('tag_id'));
|
||||
|
||||
Event::dispatch('products.tag.delete.after', $product);
|
||||
|
||||
return response()->json([
|
||||
'message' => trans('admin::app.leads.view.tags.destroy-success'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,198 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Admin\Http\Controllers\Quote;
|
||||
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Resources\Json\AnonymousResourceCollection;
|
||||
use Illuminate\Http\Response;
|
||||
use Illuminate\Support\Facades\Event;
|
||||
use Illuminate\View\View;
|
||||
use Prettus\Repository\Criteria\RequestCriteria;
|
||||
use Symfony\Component\HttpFoundation\StreamedResponse;
|
||||
use Webkul\Admin\DataGrids\Quote\QuoteDataGrid;
|
||||
use Webkul\Admin\Http\Controllers\Controller;
|
||||
use Webkul\Admin\Http\Requests\AttributeForm;
|
||||
use Webkul\Admin\Http\Requests\MassDestroyRequest;
|
||||
use Webkul\Admin\Http\Resources\QuoteResource;
|
||||
use Webkul\Core\Traits\PDFHandler;
|
||||
use Webkul\Lead\Repositories\LeadRepository;
|
||||
use Webkul\Quote\Repositories\QuoteRepository;
|
||||
|
||||
class QuoteController extends Controller
|
||||
{
|
||||
use PDFHandler;
|
||||
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(
|
||||
protected QuoteRepository $quoteRepository,
|
||||
protected LeadRepository $leadRepository
|
||||
) {
|
||||
request()->request->add(['entity_type' => 'quotes']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*/
|
||||
public function index(): View|JsonResponse
|
||||
{
|
||||
if (request()->ajax()) {
|
||||
return datagrid(QuoteDataGrid::class)->process();
|
||||
}
|
||||
|
||||
return view('admin::quotes.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*/
|
||||
public function create(): View
|
||||
{
|
||||
$lead = $this->leadRepository->find(request('id'));
|
||||
|
||||
return view('admin::quotes.create', compact('lead'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*/
|
||||
public function store(AttributeForm $request): RedirectResponse
|
||||
{
|
||||
Event::dispatch('quote.create.before');
|
||||
|
||||
$quote = $this->quoteRepository->create($request->all());
|
||||
|
||||
$leadId = request('lead_id');
|
||||
|
||||
if ($leadId) {
|
||||
$lead = $this->leadRepository->find($leadId);
|
||||
|
||||
$lead->quotes()->attach($quote->id);
|
||||
}
|
||||
|
||||
Event::dispatch('quote.create.after', $quote);
|
||||
|
||||
session()->flash('success', trans('admin::app.quotes.index.create-success'));
|
||||
|
||||
return request()->query('from') === 'lead' && $leadId
|
||||
? redirect()->route('admin.leads.view', ['id' => $leadId, 'from' => 'quotes'])
|
||||
: redirect()->route('admin.quotes.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*/
|
||||
public function edit(int $id): View
|
||||
{
|
||||
$quote = $this->quoteRepository->findOrFail($id);
|
||||
|
||||
return view('admin::quotes.edit', compact('quote'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*/
|
||||
public function update(AttributeForm $request, int $id): RedirectResponse
|
||||
{
|
||||
Event::dispatch('quote.update.before', $id);
|
||||
|
||||
$quote = $this->quoteRepository->update($request->all(), $id);
|
||||
|
||||
$quote->leads()->detach();
|
||||
|
||||
$leadId = request('lead_id');
|
||||
|
||||
if ($leadId) {
|
||||
$lead = $this->leadRepository->find($leadId);
|
||||
|
||||
$lead->quotes()->attach($quote->id);
|
||||
}
|
||||
|
||||
Event::dispatch('quote.update.after', $quote);
|
||||
|
||||
session()->flash('success', trans('admin::app.quotes.index.update-success'));
|
||||
|
||||
return request()->query('from') === 'lead' && $leadId
|
||||
? redirect()->route('admin.leads.view', ['id' => $leadId, 'from' => 'quotes'])
|
||||
: redirect()->route('admin.quotes.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Search the quotes.
|
||||
*/
|
||||
public function search(): AnonymousResourceCollection
|
||||
{
|
||||
$quotes = $this->quoteRepository
|
||||
->pushCriteria(app(RequestCriteria::class))
|
||||
->all();
|
||||
|
||||
return QuoteResource::collection($quotes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*/
|
||||
public function destroy(int $id): JsonResponse
|
||||
{
|
||||
$this->quoteRepository->findOrFail($id);
|
||||
|
||||
try {
|
||||
Event::dispatch('quote.delete.before', $id);
|
||||
|
||||
$this->quoteRepository->delete($id);
|
||||
|
||||
Event::dispatch('quote.delete.after', $id);
|
||||
|
||||
return response()->json([
|
||||
'message' => trans('admin::app.quotes.index.delete-success'),
|
||||
], 200);
|
||||
} catch (\Exception $exception) {
|
||||
return response()->json([
|
||||
'message' => trans('admin::app.quotes.index.delete-failed'),
|
||||
], 400);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mass Delete the specified resources.
|
||||
*/
|
||||
public function massDestroy(MassDestroyRequest $massDestroyRequest): JsonResponse
|
||||
{
|
||||
$quotes = $this->quoteRepository->findWhereIn('id', $massDestroyRequest->input('indices'));
|
||||
|
||||
try {
|
||||
foreach ($quotes as $quotes) {
|
||||
Event::dispatch('quote.delete.before', $quotes->id);
|
||||
|
||||
$this->quoteRepository->delete($quotes->id);
|
||||
|
||||
Event::dispatch('quote.delete.after', $quotes->id);
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'message' => trans('admin::app.quotes.index.delete-success'),
|
||||
]);
|
||||
} catch (\Exception $exception) {
|
||||
return response()->json([
|
||||
'message' => trans('admin::app.quotes.index.delete-failed'),
|
||||
], 400);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Print and download the for the specified resource.
|
||||
*/
|
||||
public function print($id): Response|StreamedResponse
|
||||
{
|
||||
$quote = $this->quoteRepository->findOrFail($id);
|
||||
|
||||
return $this->downloadPDF(
|
||||
view('admin::quotes.pdf', compact('quote'))->render(),
|
||||
'Quote_'.$quote->subject.'_'.$quote->created_at->format('d-m-Y')
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,236 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Admin\Http\Controllers\Settings;
|
||||
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Support\Facades\Event;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\View\View;
|
||||
use Webkul\Admin\DataGrids\Settings\AttributeDataGrid;
|
||||
use Webkul\Admin\Http\Controllers\Controller;
|
||||
use Webkul\Admin\Http\Requests\MassDestroyRequest;
|
||||
use Webkul\Attribute\Repositories\AttributeRepository;
|
||||
use Webkul\Attribute\Repositories\AttributeValueRepository;
|
||||
use Webkul\Core\Contracts\Validations\Code;
|
||||
|
||||
class AttributeController extends Controller
|
||||
{
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(
|
||||
protected AttributeRepository $attributeRepository,
|
||||
protected AttributeValueRepository $attributeValueRepository
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*/
|
||||
public function index(): View|JsonResponse
|
||||
{
|
||||
if (request()->ajax()) {
|
||||
return datagrid(AttributeDataGrid::class)->process();
|
||||
}
|
||||
|
||||
return view('admin::settings.attributes.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*/
|
||||
public function create(): View
|
||||
{
|
||||
return view('admin::settings.attributes.create');
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*/
|
||||
public function store(): RedirectResponse
|
||||
{
|
||||
$this->validate(request(), [
|
||||
'code' => ['required', 'unique:attributes,code,NULL,NULL,entity_type,'.request('entity_type'), new Code],
|
||||
'name' => 'required',
|
||||
'type' => 'required',
|
||||
]);
|
||||
|
||||
Event::dispatch('settings.attribute.create.before');
|
||||
|
||||
request()->request->add(['quick_add' => 1]);
|
||||
|
||||
$attribute = $this->attributeRepository->create(request()->all());
|
||||
|
||||
Event::dispatch('settings.attribute.create.after', $attribute);
|
||||
|
||||
session()->flash('success', trans('admin::app.settings.attributes.index.create-success'));
|
||||
|
||||
return redirect()->route('admin.settings.attributes.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*/
|
||||
public function edit(int $id): View
|
||||
{
|
||||
$attribute = $this->attributeRepository->findOrFail($id);
|
||||
|
||||
return view('admin::settings.attributes.edit', compact('attribute'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*/
|
||||
public function update($id): RedirectResponse
|
||||
{
|
||||
$this->validate(request(), [
|
||||
'code' => ['required', 'unique:attributes,code,NULL,NULL,entity_type,'.$id, new Code],
|
||||
'name' => 'required',
|
||||
'type' => 'required',
|
||||
]);
|
||||
|
||||
Event::dispatch('settings.attribute.update.before', $id);
|
||||
|
||||
$attribute = $this->attributeRepository->update(request()->all(), $id);
|
||||
|
||||
Event::dispatch('settings.attribute.update.after', $attribute);
|
||||
|
||||
session()->flash('success', trans('admin::app.settings.attributes.index.update-success'));
|
||||
|
||||
return redirect()->route('admin.settings.attributes.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*/
|
||||
public function destroy(int $id): JsonResponse
|
||||
{
|
||||
$attribute = $this->attributeRepository->findOrFail($id);
|
||||
|
||||
if (! $attribute->is_user_defined) {
|
||||
return response()->json([
|
||||
'message' => trans('admin::app.settings.attributes.index.user-define-error'),
|
||||
], 400);
|
||||
}
|
||||
|
||||
try {
|
||||
Event::dispatch('settings.attribute.delete.before', $id);
|
||||
|
||||
$this->attributeRepository->delete($id);
|
||||
|
||||
Event::dispatch('settings.attribute.delete.after', $id);
|
||||
|
||||
return response()->json([
|
||||
'status' => true,
|
||||
'message' => trans('admin::app.settings.attributes.index.delete-success'),
|
||||
], 200);
|
||||
} catch (\Exception $exception) {
|
||||
return response()->json([
|
||||
'message' => trans('admin::app.settings.attributes.index.delete-failed'),
|
||||
], 400);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check unique validation.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function checkUniqueValidation()
|
||||
{
|
||||
$attribute = $this->attributeRepository->findOneWhere([
|
||||
'code' => request('attribute_code'),
|
||||
]);
|
||||
|
||||
return response()->json([
|
||||
'validated' => $this->attributeValueRepository->isValueUnique(
|
||||
request('entity_id'),
|
||||
request('entity_type'),
|
||||
$attribute,
|
||||
request('attribute_value'),
|
||||
),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Search attribute lookup results
|
||||
*/
|
||||
public function lookup($lookup): JsonResponse
|
||||
{
|
||||
$results = $this->attributeRepository->getLookUpOptions($lookup, request()->input('query'));
|
||||
|
||||
return response()->json($results);
|
||||
}
|
||||
|
||||
/**
|
||||
* Search attribute lookup results
|
||||
*/
|
||||
public function lookupEntity(string $lookup): JsonResponse
|
||||
{
|
||||
$result = $this->attributeRepository->getLookUpEntity($lookup, request()->input('query'));
|
||||
|
||||
return response()->json($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mass Delete the specified resources.
|
||||
*/
|
||||
public function massDestroy(MassDestroyRequest $massDestroyRequest): JsonResponse
|
||||
{
|
||||
$count = 0;
|
||||
|
||||
$attributes = $this->attributeRepository->findWhereIn('id', $massDestroyRequest->input('indices'));
|
||||
|
||||
foreach ($attributes as $attribute) {
|
||||
$attribute = $this->attributeRepository->find($attribute->id);
|
||||
|
||||
if (! $attribute->is_user_defined) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Event::dispatch('settings.attribute.delete.before', $attribute->id);
|
||||
|
||||
$this->attributeRepository->delete($attribute->id);
|
||||
|
||||
Event::dispatch('settings.attribute.delete.after', $attribute->id);
|
||||
|
||||
$count++;
|
||||
}
|
||||
|
||||
if (! $count) {
|
||||
return response()->json([
|
||||
'message' => trans('admin::app.settings.attributes.index.mass-delete-failed'),
|
||||
], 400);
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'message' => trans('admin::app.settings.attributes.index.delete-success'),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get attribute options associated with attribute.
|
||||
*
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function getAttributeOptions(int $id)
|
||||
{
|
||||
$attribute = $this->attributeRepository->findOrFail($id);
|
||||
|
||||
return $attribute->options()->orderBy('sort_order')->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Download image or file
|
||||
*/
|
||||
public function download()
|
||||
{
|
||||
if (! request('path')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return Storage::download(request('path'));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,491 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Admin\Http\Controllers\Settings\DataTransfer;
|
||||
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Support\Facades\Event;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\View\View;
|
||||
use Webkul\Admin\DataGrids\Settings\DataTransfer\ImportDataGrid;
|
||||
use Webkul\Admin\Http\Controllers\Controller;
|
||||
use Webkul\DataTransfer\Helpers\Import;
|
||||
use Webkul\DataTransfer\Repositories\ImportRepository;
|
||||
|
||||
class ImportController extends Controller
|
||||
{
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(
|
||||
protected ImportRepository $importRepository,
|
||||
protected Import $importHelper
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*/
|
||||
public function index(): View|JsonResponse
|
||||
{
|
||||
if (request()->ajax()) {
|
||||
return datagrid(ImportDataGrid::class)->process();
|
||||
}
|
||||
|
||||
return view('admin::settings.data-transfer.imports.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*/
|
||||
public function create(): View
|
||||
{
|
||||
return view('admin::settings.data-transfer.imports.create');
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*/
|
||||
public function store(): RedirectResponse
|
||||
{
|
||||
$importers = array_keys(config('importers'));
|
||||
|
||||
$this->validate(request(), [
|
||||
'type' => 'required|in:'.implode(',', $importers),
|
||||
'action' => 'required:in:append,delete',
|
||||
'validation_strategy' => 'required:in:stop-on-errors,skip-errors',
|
||||
'allowed_errors' => 'required|integer|min:0',
|
||||
'field_separator' => 'required',
|
||||
'file' => 'required|mimes:csv,xls,xlsx,txt',
|
||||
]);
|
||||
|
||||
Event::dispatch('data_transfer.imports.create.before');
|
||||
|
||||
$data = request()->only([
|
||||
'type',
|
||||
'action',
|
||||
'process_in_queue',
|
||||
'validation_strategy',
|
||||
'validation_strategy',
|
||||
'allowed_errors',
|
||||
'field_separator',
|
||||
]);
|
||||
|
||||
if (! isset($data['process_in_queue'])) {
|
||||
$data['process_in_queue'] = false;
|
||||
} else {
|
||||
$data['process_in_queue'] = true;
|
||||
}
|
||||
|
||||
$import = $this->importRepository->create(
|
||||
array_merge(
|
||||
[
|
||||
'file_path' => request()->file('file')->storeAs(
|
||||
'imports',
|
||||
time().'-'.request()->file('file')->getClientOriginalName(),
|
||||
'public'
|
||||
),
|
||||
],
|
||||
$data
|
||||
)
|
||||
);
|
||||
|
||||
Event::dispatch('data_transfer.imports.create.after', $import);
|
||||
|
||||
session()->flash('success', trans('admin::app.settings.data-transfer.imports.create-success'));
|
||||
|
||||
return redirect()->route('admin.settings.data_transfer.imports.import', $import->id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing a new resource.
|
||||
*/
|
||||
public function edit(int $id): View
|
||||
{
|
||||
$import = $this->importRepository->findOrFail($id);
|
||||
|
||||
return view('admin::settings.data-transfer.imports.edit', compact('import'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a resource in storage.
|
||||
*/
|
||||
public function update(int $id): RedirectResponse
|
||||
{
|
||||
$importers = array_keys(config('importers'));
|
||||
|
||||
$import = $this->importRepository->findOrFail($id);
|
||||
|
||||
$this->validate(request(), [
|
||||
'type' => 'required|in:'.implode(',', $importers),
|
||||
'action' => 'required:in:append,delete',
|
||||
'validation_strategy' => 'required:in:stop-on-errors,skip-errors',
|
||||
'allowed_errors' => 'required|integer|min:0',
|
||||
'field_separator' => 'required',
|
||||
'file' => 'mimes:csv,xls,xlsx,txt',
|
||||
]);
|
||||
|
||||
Event::dispatch('data_transfer.imports.update.before');
|
||||
|
||||
$data = array_merge(
|
||||
request()->only([
|
||||
'type',
|
||||
'action',
|
||||
'process_in_queue',
|
||||
'validation_strategy',
|
||||
'validation_strategy',
|
||||
'allowed_errors',
|
||||
'field_separator',
|
||||
]),
|
||||
[
|
||||
'state' => 'pending',
|
||||
'processed_rows_count' => 0,
|
||||
'invalid_rows_count' => 0,
|
||||
'errors_count' => 0,
|
||||
'errors' => null,
|
||||
'error_file_path' => null,
|
||||
'started_at' => null,
|
||||
'completed_at' => null,
|
||||
'summary' => null,
|
||||
]
|
||||
);
|
||||
|
||||
Storage::disk('public')->delete($import->error_file_path ?? '');
|
||||
|
||||
if (request()->file('file') && request()->file('file')->isValid()) {
|
||||
Storage::disk('public')->delete($import->file_path);
|
||||
|
||||
$data['file_path'] = request()->file('file')->storeAs(
|
||||
'imports',
|
||||
time().'-'.request()->file('file')->getClientOriginalName(),
|
||||
'public'
|
||||
);
|
||||
}
|
||||
|
||||
if (! isset($data['process_in_queue'])) {
|
||||
$data['process_in_queue'] = false;
|
||||
}
|
||||
|
||||
$import = $this->importRepository->update($data, $import->id);
|
||||
|
||||
Event::dispatch('data_transfer.imports.update.after', $import);
|
||||
|
||||
session()->flash('success', trans('admin::app.settings.data-transfer.imports.update-success'));
|
||||
|
||||
return redirect()->route('admin.settings.data_transfer.imports.import', $import->id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*/
|
||||
public function destroy(int $id): JsonResponse
|
||||
{
|
||||
$import = $this->importRepository->findOrFail($id);
|
||||
|
||||
try {
|
||||
Storage::disk('public')->delete($import->file_path);
|
||||
|
||||
Storage::disk('public')->delete($import->error_file_path ?? '');
|
||||
|
||||
$this->importRepository->delete($id);
|
||||
|
||||
return response()->json([
|
||||
'message' => trans('admin::app.settings.data-transfer.imports.delete-success'),
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'message' => trans('admin::app.settings.data-transfer.imports.delete-failed'),
|
||||
], 500);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*/
|
||||
public function import(int $id): View
|
||||
{
|
||||
$import = $this->importRepository->findOrFail($id);
|
||||
|
||||
$isValid = $this->importHelper
|
||||
->setImport($import)
|
||||
->isValid();
|
||||
|
||||
if ($import->state == Import::STATE_LINKING) {
|
||||
if ($this->importHelper->isIndexingRequired()) {
|
||||
$state = Import::STATE_INDEXING;
|
||||
} else {
|
||||
$state = Import::STATE_COMPLETED;
|
||||
}
|
||||
} elseif ($import->state == Import::STATE_INDEXING) {
|
||||
$state = Import::STATE_COMPLETED;
|
||||
} else {
|
||||
$state = Import::STATE_COMPLETED;
|
||||
}
|
||||
|
||||
$stats = $this->importHelper->stats($state);
|
||||
|
||||
$import->unsetRelations();
|
||||
|
||||
return view('admin::settings.data-transfer.imports.import', compact('import', 'isValid', 'stats'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*/
|
||||
public function validateImport(int $id): JsonResponse
|
||||
{
|
||||
$import = $this->importRepository->findOrFail($id);
|
||||
|
||||
$isValid = $this->importHelper
|
||||
->setImport($import)
|
||||
->validate();
|
||||
|
||||
return new JsonResponse([
|
||||
'is_valid' => $isValid,
|
||||
'import' => $this->importHelper->getImport()->unsetRelations(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*/
|
||||
public function start(int $id): JsonResponse
|
||||
{
|
||||
$import = $this->importRepository->findOrFail($id);
|
||||
|
||||
if (! $import->processed_rows_count) {
|
||||
return new JsonResponse([
|
||||
'message' => trans('admin::app.settings.data-transfer.imports.nothing-to-import'),
|
||||
], 400);
|
||||
}
|
||||
|
||||
$this->importHelper->setImport($import);
|
||||
|
||||
if (! $this->importHelper->isValid()) {
|
||||
return new JsonResponse([
|
||||
'message' => trans('admin::app.settings.data-transfer.imports.not-valid'),
|
||||
], 400);
|
||||
}
|
||||
|
||||
if (
|
||||
$import->process_in_queue
|
||||
&& config('queue.default') == 'sync'
|
||||
) {
|
||||
return new JsonResponse([
|
||||
'message' => trans('admin::app.settings.data-transfer.imports.setup-queue-error'),
|
||||
], 400);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the import state to processing
|
||||
*/
|
||||
if ($import->state == Import::STATE_VALIDATED) {
|
||||
$this->importHelper->started();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the first pending batch to import
|
||||
*/
|
||||
$importBatch = $import->batches->where('state', Import::STATE_PENDING)->first();
|
||||
|
||||
if ($importBatch) {
|
||||
/**
|
||||
* Start the import process
|
||||
*/
|
||||
try {
|
||||
if ($import->process_in_queue) {
|
||||
$this->importHelper->start();
|
||||
} else {
|
||||
$this->importHelper->start($importBatch);
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
return new JsonResponse([
|
||||
'message' => $e->getMessage(),
|
||||
], 400);
|
||||
}
|
||||
} else {
|
||||
if ($this->importHelper->isLinkingRequired()) {
|
||||
$this->importHelper->linking();
|
||||
} elseif ($this->importHelper->isIndexingRequired()) {
|
||||
$this->importHelper->indexing();
|
||||
} else {
|
||||
$this->importHelper->completed();
|
||||
}
|
||||
}
|
||||
|
||||
return new JsonResponse([
|
||||
'stats' => $this->importHelper->stats(Import::STATE_PROCESSED),
|
||||
'import' => $this->importHelper->getImport()->unsetRelations(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*/
|
||||
public function link(int $id): JsonResponse
|
||||
{
|
||||
$import = $this->importRepository->findOrFail($id);
|
||||
|
||||
if (! $import->processed_rows_count) {
|
||||
return new JsonResponse([
|
||||
'message' => trans('admin::app.settings.data-transfer.imports.nothing-to-import'),
|
||||
], 400);
|
||||
}
|
||||
|
||||
$this->importHelper->setImport($import);
|
||||
|
||||
if (! $this->importHelper->isValid()) {
|
||||
return new JsonResponse([
|
||||
'message' => trans('admin::app.settings.data-transfer.imports.not-valid'),
|
||||
], 400);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the import state to linking
|
||||
*/
|
||||
if ($import->state == Import::STATE_PROCESSED) {
|
||||
$this->importHelper->linking();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the first processing batch to link
|
||||
*/
|
||||
$importBatch = $import->batches->where('state', Import::STATE_PROCESSED)->first();
|
||||
|
||||
/**
|
||||
* Set the import state to linking/completed
|
||||
*/
|
||||
if ($importBatch) {
|
||||
/**
|
||||
* Start the resource linking process
|
||||
*/
|
||||
try {
|
||||
$this->importHelper->link($importBatch);
|
||||
} catch (\Exception $e) {
|
||||
return new JsonResponse([
|
||||
'message' => $e->getMessage(),
|
||||
], 400);
|
||||
}
|
||||
} else {
|
||||
if ($this->importHelper->isIndexingRequired()) {
|
||||
$this->importHelper->indexing();
|
||||
} else {
|
||||
$this->importHelper->completed();
|
||||
}
|
||||
}
|
||||
|
||||
return new JsonResponse([
|
||||
'stats' => $this->importHelper->stats(Import::STATE_LINKED),
|
||||
'import' => $this->importHelper->getImport()->unsetRelations(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*/
|
||||
public function indexData(int $id): JsonResponse
|
||||
{
|
||||
$import = $this->importRepository->findOrFail($id);
|
||||
|
||||
if (! $import->processed_rows_count) {
|
||||
return new JsonResponse([
|
||||
'message' => trans('admin::app.settings.data-transfer.imports.nothing-to-import'),
|
||||
], 400);
|
||||
}
|
||||
|
||||
$this->importHelper->setImport($import);
|
||||
|
||||
if (! $this->importHelper->isValid()) {
|
||||
return new JsonResponse([
|
||||
'message' => trans('admin::app.settings.data-transfer.imports.not-valid'),
|
||||
], 400);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the import state to linking
|
||||
*/
|
||||
if ($import->state == Import::STATE_LINKED) {
|
||||
$this->importHelper->indexing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the first processing batch to link
|
||||
*/
|
||||
$importBatch = $import->batches->where('state', Import::STATE_LINKED)->first();
|
||||
|
||||
/**
|
||||
* Set the import state to linking/completed
|
||||
*/
|
||||
if ($importBatch) {
|
||||
/**
|
||||
* Start the resource linking process
|
||||
*/
|
||||
try {
|
||||
$this->importHelper->index($importBatch);
|
||||
} catch (\Exception $e) {
|
||||
return new JsonResponse([
|
||||
'message' => $e->getMessage(),
|
||||
], 400);
|
||||
}
|
||||
} else {
|
||||
/**
|
||||
* Set the import state to completed
|
||||
*/
|
||||
$this->importHelper->completed();
|
||||
}
|
||||
|
||||
return new JsonResponse([
|
||||
'stats' => $this->importHelper->stats(Import::STATE_INDEXED),
|
||||
'import' => $this->importHelper->getImport()->unsetRelations(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns import stats
|
||||
*/
|
||||
public function stats(int $id, string $state = Import::STATE_PROCESSED): JsonResponse
|
||||
{
|
||||
$import = $this->importRepository->findOrFail($id);
|
||||
|
||||
$stats = $this->importHelper
|
||||
->setImport($import)
|
||||
->stats($state);
|
||||
|
||||
return new JsonResponse([
|
||||
'stats' => $stats,
|
||||
'import' => $this->importHelper->getImport()->unsetRelations(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Download import error report
|
||||
*/
|
||||
public function downloadSample(string $type)
|
||||
{
|
||||
$importer = config('importers.'.$type);
|
||||
|
||||
return Storage::download($importer['sample_path']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Download import error report
|
||||
*/
|
||||
public function download(int $id)
|
||||
{
|
||||
$import = $this->importRepository->findOrFail($id);
|
||||
|
||||
return Storage::disk('public')->download($import->file_path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Download import error report
|
||||
*/
|
||||
public function downloadErrorReport(int $id)
|
||||
{
|
||||
$import = $this->importRepository->findOrFail($id);
|
||||
|
||||
return Storage::disk('public')->download($import->file_path);
|
||||
}
|
||||
}
|
||||
133
packages/Webkul/Admin/src/Http/Controllers/Settings/EmailTemplateController.php
Executable file
133
packages/Webkul/Admin/src/Http/Controllers/Settings/EmailTemplateController.php
Executable file
@@ -0,0 +1,133 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Admin\Http\Controllers\Settings;
|
||||
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Support\Facades\Event;
|
||||
use Illuminate\View\View;
|
||||
use Webkul\Admin\DataGrids\Settings\EmailTemplateDataGrid;
|
||||
use Webkul\Admin\Http\Controllers\Controller;
|
||||
use Webkul\Automation\Helpers\Entity;
|
||||
use Webkul\EmailTemplate\Repositories\EmailTemplateRepository;
|
||||
|
||||
class EmailTemplateController extends Controller
|
||||
{
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(
|
||||
protected EmailTemplateRepository $emailTemplateRepository,
|
||||
protected Entity $workflowEntityHelper
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Display a listing of the email template.
|
||||
*/
|
||||
public function index(): View|JsonResponse
|
||||
{
|
||||
if (request()->ajax()) {
|
||||
return datagrid(EmailTemplateDataGrid::class)->process();
|
||||
}
|
||||
|
||||
return view('admin::settings.email-templates.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
$placeholders = $this->workflowEntityHelper->getEmailTemplatePlaceholders();
|
||||
|
||||
return view('admin::settings.email-templates.create', compact('placeholders'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created email templates in storage.
|
||||
*/
|
||||
public function store(): RedirectResponse
|
||||
{
|
||||
$this->validate(request(), [
|
||||
'name' => 'required|unique:email_templates,name',
|
||||
'subject' => 'required',
|
||||
'content' => 'required',
|
||||
]);
|
||||
|
||||
Event::dispatch('settings.email_templates.create.before');
|
||||
|
||||
$emailTemplate = $this->emailTemplateRepository->create(request()->all());
|
||||
|
||||
Event::dispatch('settings.email_templates.create.after', $emailTemplate);
|
||||
|
||||
session()->flash('success', trans('admin::app.settings.email-template.index.create-success'));
|
||||
|
||||
return redirect()->route('admin.settings.email_templates.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified email template.
|
||||
*/
|
||||
public function edit(int $id): View
|
||||
{
|
||||
$emailTemplate = $this->emailTemplateRepository->findOrFail($id);
|
||||
|
||||
$placeholders = $this->workflowEntityHelper->getEmailTemplatePlaceholders();
|
||||
|
||||
return view('admin::settings.email-templates.edit', compact('emailTemplate', 'placeholders'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified email template in storage.
|
||||
*/
|
||||
public function update(int $id): RedirectResponse
|
||||
{
|
||||
$this->validate(request(), [
|
||||
'name' => 'required|unique:email_templates,name,'.$id,
|
||||
'subject' => 'required',
|
||||
'content' => 'required',
|
||||
]);
|
||||
|
||||
Event::dispatch('settings.email_templates.update.before', $id);
|
||||
|
||||
$emailTemplate = $this->emailTemplateRepository->update(request()->all(), $id);
|
||||
|
||||
Event::dispatch('settings.email_templates.update.after', $emailTemplate);
|
||||
|
||||
session()->flash('success', trans('admin::app.settings.email-template.index.update-success'));
|
||||
|
||||
return redirect()->route('admin.settings.email_templates.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified email template from storage.
|
||||
*/
|
||||
public function destroy(int $id): JsonResponse
|
||||
{
|
||||
$emailTemplate = $this->emailTemplateRepository->findOrFail($id);
|
||||
|
||||
try {
|
||||
Event::dispatch('settings.email_templates.delete.before', $id);
|
||||
|
||||
$emailTemplate->delete($id);
|
||||
|
||||
Event::dispatch('settings.email_templates.delete.after', $id);
|
||||
|
||||
return response()->json([
|
||||
'message' => trans('admin::app.settings.email-template.index.delete-success'),
|
||||
], 200);
|
||||
} catch (\Exception $exception) {
|
||||
return response()->json([
|
||||
'message' => trans('admin::app.settings.email-template.index.delete-failed'),
|
||||
], 400);
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'message' => trans('admin::app.settings.email-template.index.delete-failed'),
|
||||
], 400);
|
||||
}
|
||||
}
|
||||
127
packages/Webkul/Admin/src/Http/Controllers/Settings/GroupController.php
Executable file
127
packages/Webkul/Admin/src/Http/Controllers/Settings/GroupController.php
Executable file
@@ -0,0 +1,127 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Admin\Http\Controllers\Settings;
|
||||
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
use Illuminate\Support\Facades\Event;
|
||||
use Illuminate\View\View;
|
||||
use Webkul\Admin\DataGrids\Settings\GroupDataGrid;
|
||||
use Webkul\Admin\Http\Controllers\Controller;
|
||||
use Webkul\User\Repositories\GroupRepository;
|
||||
|
||||
class GroupController extends Controller
|
||||
{
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(protected GroupRepository $groupRepository) {}
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*/
|
||||
public function index(): View|JsonResponse
|
||||
{
|
||||
if (request()->ajax()) {
|
||||
return datagrid(GroupDataGrid::class)->process();
|
||||
}
|
||||
|
||||
return view('admin::settings.groups.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*/
|
||||
public function store(): JsonResponse
|
||||
{
|
||||
$this->validate(request(), [
|
||||
'name' => 'required|unique:groups,name|max:50',
|
||||
'description' => 'required|max:250',
|
||||
]);
|
||||
|
||||
Event::dispatch('settings.group.create.before');
|
||||
|
||||
$group = $this->groupRepository->create(request()->only([
|
||||
'name',
|
||||
'description',
|
||||
]));
|
||||
|
||||
Event::dispatch('settings.group.create.after', $group);
|
||||
|
||||
return new JsonResponse([
|
||||
'data' => $group,
|
||||
'message' => trans('admin::app.settings.groups.index.create-success'),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*/
|
||||
public function edit(int $id): JsonResource
|
||||
{
|
||||
$group = $this->groupRepository->findOrFail($id);
|
||||
|
||||
return new JsonResource([
|
||||
'data' => $group,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*/
|
||||
public function update(int $id): JsonResponse
|
||||
{
|
||||
$this->validate(request(), [
|
||||
'name' => 'required|max:50|unique:groups,name,'.$id,
|
||||
'description' => 'required|max:250',
|
||||
]);
|
||||
|
||||
Event::dispatch('settings.group.update.before', $id);
|
||||
|
||||
$group = $this->groupRepository->update(request()->only([
|
||||
'name',
|
||||
'description',
|
||||
]), $id);
|
||||
|
||||
Event::dispatch('settings.group.update.after', $group);
|
||||
|
||||
return new JsonResponse([
|
||||
'data' => $group,
|
||||
'message' => trans('admin::app.settings.groups.index.update-success'),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function destroy(int $id): JsonResponse
|
||||
{
|
||||
$group = $this->groupRepository->findOrFail($id);
|
||||
|
||||
if ($group->users()->exists()) {
|
||||
return response()->json([
|
||||
'message' => trans('admin::app.settings.groups.index.delete-failed-associated-users'),
|
||||
], 400);
|
||||
}
|
||||
|
||||
try {
|
||||
Event::dispatch('settings.group.delete.before', $id);
|
||||
|
||||
$group->delete($id);
|
||||
|
||||
Event::dispatch('settings.group.delete.after', $id);
|
||||
|
||||
return new JsonResponse([
|
||||
'message' => trans('admin::app.settings.groups.index.destroy-success'),
|
||||
], 200);
|
||||
} catch (\Exception $exception) {
|
||||
return new JsonResponse([
|
||||
'message' => trans('admin::app.settings.groups.index.delete-failed'),
|
||||
], 400);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Admin\Http\Controllers\Settings;
|
||||
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Support\Facades\Event;
|
||||
use Prettus\Repository\Criteria\RequestCriteria;
|
||||
use Webkul\Admin\Http\Controllers\Controller;
|
||||
use Webkul\Admin\Http\Requests\AttributeForm;
|
||||
use Webkul\Warehouse\Repositories\LocationRepository;
|
||||
|
||||
class LocationController extends Controller
|
||||
{
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(protected LocationRepository $locationRepository) {}
|
||||
|
||||
/**
|
||||
* Search location results
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function search()
|
||||
{
|
||||
$results = $this->locationRepository
|
||||
->pushCriteria(app(RequestCriteria::class))
|
||||
->all();
|
||||
|
||||
return response()->json([
|
||||
'data' => $results,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*/
|
||||
public function store(AttributeForm $request): JsonResponse
|
||||
{
|
||||
Event::dispatch('settings.location.create.before');
|
||||
|
||||
$location = $this->locationRepository->create(request()->all());
|
||||
|
||||
Event::dispatch('settings.location.create.after', $location);
|
||||
|
||||
return new JsonResponse([
|
||||
'data' => $location,
|
||||
'message' => trans('admin::app.settings.warehouses.view.locations.create-success'),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function destroy(int $id): JsonResponse
|
||||
{
|
||||
$this->locationRepository->findOrFail($id);
|
||||
|
||||
try {
|
||||
Event::dispatch('settings.location.delete.before', $id);
|
||||
|
||||
$this->locationRepository->delete($id);
|
||||
|
||||
Event::dispatch('settings.location.delete.after', $id);
|
||||
|
||||
return new JsonResponse([
|
||||
'message' => trans('admin::app.settings.warehouses.view.locations.delete-success'),
|
||||
], 200);
|
||||
} catch (\Exception $exception) {
|
||||
return new JsonResponse([
|
||||
'message' => trans('admin::app.settings.warehouses.view.locations.delete-failed'),
|
||||
], 400);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Admin\Http\Controllers\Settings\Marketing;
|
||||
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Support\Facades\Event;
|
||||
use Illuminate\View\View;
|
||||
use Webkul\Admin\DataGrids\Settings\Marketing\CampaignDatagrid;
|
||||
use Webkul\Admin\Http\Controllers\Controller;
|
||||
use Webkul\Admin\Http\Requests\MassDestroyRequest;
|
||||
use Webkul\EmailTemplate\Repositories\EmailTemplateRepository;
|
||||
use Webkul\Marketing\Repositories\CampaignRepository;
|
||||
use Webkul\Marketing\Repositories\EventRepository;
|
||||
|
||||
class CampaignsController extends Controller
|
||||
{
|
||||
/**
|
||||
* Create new a controller instance.
|
||||
*/
|
||||
public function __construct(
|
||||
protected CampaignRepository $campaignRepository,
|
||||
protected EventRepository $eventRepository,
|
||||
protected EmailTemplateRepository $emailTemplateRepository,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Display a listing of the marketing campaigns.
|
||||
*/
|
||||
public function index(): View|JsonResponse
|
||||
{
|
||||
if (request()->isXmlHttpRequest()) {
|
||||
return datagrid(CampaignDatagrid::class)->process();
|
||||
}
|
||||
|
||||
return view('admin::settings.marketing.campaigns.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get marketing events.
|
||||
*/
|
||||
public function getEvents(): JsonResponse
|
||||
{
|
||||
$events = $this->eventRepository->get(['id', 'name']);
|
||||
|
||||
return response()->json([
|
||||
'data' => $events,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Email Templates.
|
||||
*/
|
||||
public function getEmailTemplates(): JsonResponse
|
||||
{
|
||||
$emailTemplates = $this->emailTemplateRepository->get(['id', 'name']);
|
||||
|
||||
return response()->json([
|
||||
'data' => $emailTemplates,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created marketing campaign in storage.
|
||||
*/
|
||||
public function store(): JsonResponse
|
||||
{
|
||||
$validatedData = $this->validate(request(), [
|
||||
'name' => 'required|string|max:255',
|
||||
'subject' => 'required|string|max:255',
|
||||
'marketing_template_id' => 'required|exists:email_templates,id',
|
||||
'marketing_event_id' => 'required|exists:marketing_events,id',
|
||||
'status' => 'sometimes|required|in:0,1',
|
||||
]);
|
||||
|
||||
Event::dispatch('settings.marketing.campaigns.create.before');
|
||||
|
||||
$marketingCampaign = $this->campaignRepository->create($validatedData);
|
||||
|
||||
Event::dispatch('settings.marketing.campaigns.create.after', $marketingCampaign);
|
||||
|
||||
return response()->json([
|
||||
'message' => trans('admin::app.settings.marketing.campaigns.index.create-success'),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the specified Resource.
|
||||
*/
|
||||
public function show(int $id): JsonResponse
|
||||
{
|
||||
$campaign = $this->campaignRepository->findOrFail($id);
|
||||
|
||||
return response()->json([
|
||||
'data' => $campaign,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified marketing campaign in storage.
|
||||
*/
|
||||
public function update(int $id): JsonResponse
|
||||
{
|
||||
$validatedData = $this->validate(request(), [
|
||||
'name' => 'required|string|max:255',
|
||||
'subject' => 'required|string|max:255',
|
||||
'marketing_template_id' => 'required|exists:email_templates,id',
|
||||
'marketing_event_id' => 'required|exists:marketing_events,id',
|
||||
'status' => 'sometimes|required|in:0,1',
|
||||
]);
|
||||
|
||||
Event::dispatch('settings.marketing.campaigns.update.before', $id);
|
||||
|
||||
$marketingCampaign = $this->campaignRepository->update($validatedData, $id);
|
||||
|
||||
Event::dispatch('settings.marketing.campaigns.update.after', $marketingCampaign);
|
||||
|
||||
return response()->json([
|
||||
'message' => trans('admin::app.settings.marketing.campaigns.index.update-success'),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified marketing campaign from storage.
|
||||
*/
|
||||
public function destroy(int $id): JsonResponse
|
||||
{
|
||||
Event::dispatch('settings.marketing.campaigns.delete.before', $id);
|
||||
|
||||
$this->campaignRepository->delete($id);
|
||||
|
||||
Event::dispatch('settings.marketing.campaigns.delete.after', $id);
|
||||
|
||||
return response()->json([
|
||||
'message' => trans('admin::app.settings.marketing.campaigns.index.delete-success'),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified marketing campaigns from storage.
|
||||
*/
|
||||
public function massDestroy(MassDestroyRequest $massDestroyRequest): JsonResponse
|
||||
{
|
||||
$campaigns = $this->campaignRepository->findWhereIn('id', $massDestroyRequest->input('indices'));
|
||||
|
||||
foreach ($campaigns as $campaign) {
|
||||
Event::dispatch('settings.marketing.campaigns.delete.before', $campaign);
|
||||
|
||||
$this->campaignRepository->delete($campaign->id);
|
||||
|
||||
Event::dispatch('settings.marketing.campaigns.delete.after', $campaign);
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'message' => trans('admin::app.settings.marketing.campaigns.index.mass-delete-success'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Admin\Http\Controllers\Settings\Marketing;
|
||||
|
||||
use Exception;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Support\Facades\Event;
|
||||
use Illuminate\View\View;
|
||||
use Webkul\Admin\DataGrids\Settings\Marketing\EventDataGrid;
|
||||
use Webkul\Admin\Http\Controllers\Controller;
|
||||
use Webkul\Admin\Http\Requests\MassDestroyRequest;
|
||||
use Webkul\Marketing\Repositories\EventRepository;
|
||||
|
||||
class EventController extends Controller
|
||||
{
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
*/
|
||||
public function __construct(protected EventRepository $eventRepository) {}
|
||||
|
||||
/**
|
||||
* Display a listing of the marketing events.
|
||||
*/
|
||||
public function index(): View|JsonResponse
|
||||
{
|
||||
if (request()->ajax()) {
|
||||
return datagrid(EventDataGrid::class)->process();
|
||||
}
|
||||
|
||||
return view('admin::settings.marketing.events.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created marketing event in storage.
|
||||
*/
|
||||
public function store(): JsonResponse
|
||||
{
|
||||
$validatedData = $this->validate(request(), [
|
||||
'name' => 'required|max:60',
|
||||
'description' => 'required',
|
||||
'date' => 'required|date|after_or_equal:today',
|
||||
]);
|
||||
|
||||
Event::dispatch('settings.marketing.events.create.before');
|
||||
|
||||
$marketingEvent = $this->eventRepository->create($validatedData);
|
||||
|
||||
Event::dispatch('settings.marketing.events.create.after', $marketingEvent);
|
||||
|
||||
return response()->json([
|
||||
'message' => trans('admin::app.settings.marketing.events.index.create-success'),
|
||||
'data' => $marketingEvent,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified marketing event in storage.
|
||||
*/
|
||||
public function update(int $id): JsonResponse
|
||||
{
|
||||
$validatedData = $this->validate(request(), [
|
||||
'name' => 'required|max:60',
|
||||
'description' => 'required',
|
||||
'date' => 'required|date|after_or_equal:today',
|
||||
]);
|
||||
|
||||
Event::dispatch('settings.marketing.events.update.before', $id);
|
||||
|
||||
$marketingEvent = $this->eventRepository->update($validatedData, $id);
|
||||
|
||||
Event::dispatch('settings.marketing.events.update.after', $marketingEvent);
|
||||
|
||||
return response()->json([
|
||||
'message' => trans('admin::app.settings.marketing.events.index.update-success'),
|
||||
'data' => $marketingEvent,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified marketing event from storage.
|
||||
*/
|
||||
public function destroy(int $id): JsonResponse
|
||||
{
|
||||
$event = $this->eventRepository->findOrFail($id);
|
||||
|
||||
if ($event->campaigns->isNotEmpty()) {
|
||||
return response()->json([
|
||||
'message' => trans('admin::app.settings.marketing.events.index.delete-failed-associated-campaigns'),
|
||||
], 422);
|
||||
}
|
||||
|
||||
Event::dispatch('settings.marketing.events.delete.before', $event);
|
||||
|
||||
$this->eventRepository->delete($event->id);
|
||||
|
||||
Event::dispatch('settings.marketing.events.delete.after', $event);
|
||||
|
||||
return response()->json([
|
||||
'message' => trans('admin::app.settings.marketing.events.index.delete-success'),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified marketing events from storage.
|
||||
*/
|
||||
public function massDestroy(MassDestroyRequest $request): JsonResponse
|
||||
{
|
||||
try {
|
||||
$events = $this->eventRepository->findWhereIn('id', $request->input('indices', []));
|
||||
|
||||
$deletedCount = 0;
|
||||
|
||||
$blockedCount = 0;
|
||||
|
||||
foreach ($events as $event) {
|
||||
if (
|
||||
$event->campaigns
|
||||
&& $event->campaigns->isNotEmpty()
|
||||
) {
|
||||
$blockedCount++;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
Event::dispatch('settings.marketing.events.delete.before', $event);
|
||||
|
||||
$this->eventRepository->delete($event->id);
|
||||
|
||||
Event::dispatch('settings.marketing.events.delete.after', $event);
|
||||
|
||||
$deletedCount++;
|
||||
}
|
||||
|
||||
$statusCode = 200;
|
||||
|
||||
switch (true) {
|
||||
case $deletedCount > 0 && $blockedCount === 0:
|
||||
$message = trans('admin::app.settings.marketing.events.index.mass-delete-success');
|
||||
|
||||
break;
|
||||
|
||||
case $deletedCount > 0 && $blockedCount > 0:
|
||||
$message = trans('admin::app.settings.marketing.events.index.partial-delete-warning');
|
||||
|
||||
break;
|
||||
|
||||
case $deletedCount === 0 && $blockedCount > 0:
|
||||
$message = trans('admin::app.settings.marketing.events.index.none-delete-warning');
|
||||
|
||||
$statusCode = 400;
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
$message = trans('admin::app.settings.marketing.events.index.no-selection');
|
||||
|
||||
$statusCode = 400;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return response()->json(['message' => $message], $statusCode);
|
||||
} catch (Exception $e) {
|
||||
return response()->json([
|
||||
'message' => trans('admin::app.settings.marketing.events.index.mass-delete-failed'),
|
||||
], 400);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Admin\Http\Controllers\Settings;
|
||||
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Support\Facades\Event;
|
||||
use Illuminate\View\View;
|
||||
use Webkul\Admin\DataGrids\Settings\PipelineDataGrid;
|
||||
use Webkul\Admin\Http\Controllers\Controller;
|
||||
use Webkul\Admin\Http\Requests\PipelineForm;
|
||||
use Webkul\Lead\Repositories\PipelineRepository;
|
||||
|
||||
class PipelineController extends Controller
|
||||
{
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(protected PipelineRepository $pipelineRepository) {}
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*/
|
||||
public function index(): View|JsonResponse
|
||||
{
|
||||
if (request()->ajax()) {
|
||||
return datagrid(PipelineDataGrid::class)->process();
|
||||
}
|
||||
|
||||
return view('admin::settings.pipelines.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*/
|
||||
public function create(): View
|
||||
{
|
||||
return view('admin::settings.pipelines.create');
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*/
|
||||
public function store(PipelineForm $request): RedirectResponse
|
||||
{
|
||||
$request->validated();
|
||||
|
||||
$request->merge([
|
||||
'is_default' => request()->has('is_default') ? 1 : 0,
|
||||
]);
|
||||
|
||||
Event::dispatch('settings.pipeline.create.before');
|
||||
|
||||
$pipeline = $this->pipelineRepository->create($request->all());
|
||||
|
||||
Event::dispatch('settings.pipeline.create.after', $pipeline);
|
||||
|
||||
session()->flash('success', trans('admin::app.settings.pipelines.index.create-success'));
|
||||
|
||||
return redirect()->route('admin.settings.pipelines.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*/
|
||||
public function edit(int $id): View
|
||||
{
|
||||
$pipeline = $this->pipelineRepository->findOrFail($id);
|
||||
|
||||
return view('admin::settings.pipelines.edit', compact('pipeline'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*/
|
||||
public function update(PipelineForm $request, int $id): RedirectResponse
|
||||
{
|
||||
$request->validated();
|
||||
|
||||
$isDefault = request()->has('is_default') ? 1 : 0;
|
||||
|
||||
if (! $isDefault) {
|
||||
$defaultCount = $this->pipelineRepository->findWhere(['is_default' => 1])->count();
|
||||
|
||||
$pipeline = $this->pipelineRepository->find($id);
|
||||
|
||||
if (
|
||||
$defaultCount === 1
|
||||
&& $pipeline->is_default
|
||||
) {
|
||||
session()->flash('error', trans('admin::app.settings.pipelines.index.default-required'));
|
||||
|
||||
return redirect()->back();
|
||||
}
|
||||
}
|
||||
|
||||
$request->merge(['is_default' => $isDefault]);
|
||||
|
||||
Event::dispatch('settings.pipeline.update.before', $id);
|
||||
|
||||
$pipeline = $this->pipelineRepository->update($request->all(), $id);
|
||||
|
||||
Event::dispatch('settings.pipeline.update.after', $pipeline);
|
||||
|
||||
session()->flash('success', trans('admin::app.settings.pipelines.index.update-success'));
|
||||
|
||||
return redirect()->route('admin.settings.pipelines.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*/
|
||||
public function destroy($id): JsonResponse
|
||||
{
|
||||
$pipeline = $this->pipelineRepository->findOrFail($id);
|
||||
|
||||
if ($pipeline->is_default) {
|
||||
return response()->json([
|
||||
'message' => trans('admin::app.settings.pipelines.index.default-delete-error'),
|
||||
], 400);
|
||||
} else {
|
||||
$defaultPipeline = $this->pipelineRepository->getDefaultPipeline();
|
||||
|
||||
$pipeline->leads()->update([
|
||||
'lead_pipeline_id' => $defaultPipeline->id,
|
||||
'lead_pipeline_stage_id' => $defaultPipeline->stages()->first()->id,
|
||||
]);
|
||||
}
|
||||
|
||||
try {
|
||||
Event::dispatch('settings.pipeline.delete.before', $id);
|
||||
|
||||
$this->pipelineRepository->delete($id);
|
||||
|
||||
Event::dispatch('settings.pipeline.delete.after', $id);
|
||||
|
||||
return response()->json([
|
||||
'message' => trans('admin::app.settings.pipelines.index.delete-success'),
|
||||
], 200);
|
||||
} catch (\Exception $exception) {
|
||||
return response()->json([
|
||||
'message' => trans('admin::app.settings.pipelines.index.delete-failed'),
|
||||
], 400);
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'message' => trans('admin::app.settings.pipelines.index.delete-failed'),
|
||||
], 400);
|
||||
}
|
||||
}
|
||||
168
packages/Webkul/Admin/src/Http/Controllers/Settings/RoleController.php
Executable file
168
packages/Webkul/Admin/src/Http/Controllers/Settings/RoleController.php
Executable file
@@ -0,0 +1,168 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Admin\Http\Controllers\Settings;
|
||||
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Support\Facades\Event;
|
||||
use Illuminate\View\View;
|
||||
use Webkul\Admin\DataGrids\Settings\RoleDataGrid;
|
||||
use Webkul\Admin\Http\Controllers\Controller;
|
||||
use Webkul\User\Repositories\RoleRepository;
|
||||
|
||||
class RoleController extends Controller
|
||||
{
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(protected RoleRepository $roleRepository) {}
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*/
|
||||
public function index(): View|JsonResponse
|
||||
{
|
||||
if (request()->ajax()) {
|
||||
return datagrid(RoleDataGrid::class)->process();
|
||||
}
|
||||
|
||||
return view('admin::settings.roles.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*/
|
||||
public function create(): View
|
||||
{
|
||||
return view('admin::settings.roles.create');
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*/
|
||||
public function store(): RedirectResponse
|
||||
{
|
||||
$this->validate(request(), [
|
||||
'name' => 'required',
|
||||
'permission_type' => 'required|in:all,custom',
|
||||
'description' => 'required',
|
||||
]);
|
||||
|
||||
if (request('permission_type') == 'custom') {
|
||||
$this->validate(request(), [
|
||||
'permissions' => 'required',
|
||||
]);
|
||||
}
|
||||
|
||||
Event::dispatch('settings.role.create.before');
|
||||
|
||||
$data = request()->only([
|
||||
'name',
|
||||
'description',
|
||||
'permission_type',
|
||||
'permissions',
|
||||
]);
|
||||
|
||||
$role = $this->roleRepository->create($data);
|
||||
|
||||
Event::dispatch('settings.role.create.after', $role);
|
||||
|
||||
session()->flash('success', trans('admin::app.settings.roles.index.create-success'));
|
||||
|
||||
return redirect()->route('admin.settings.roles.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*/
|
||||
public function edit(int $id): View
|
||||
{
|
||||
$role = $this->roleRepository->findOrFail($id);
|
||||
|
||||
return view('admin::settings.roles.edit', compact('role'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*/
|
||||
public function update(int $id): RedirectResponse
|
||||
{
|
||||
$this->validate(request(), [
|
||||
'name' => 'required',
|
||||
'permission_type' => 'required|in:all,custom',
|
||||
'description' => 'required',
|
||||
'permissions' => 'required_if:permission_type,custom',
|
||||
]);
|
||||
|
||||
Event::dispatch('settings.role.update.before', $id);
|
||||
|
||||
$data = array_merge(request()->only([
|
||||
'name',
|
||||
'description',
|
||||
'permission_type',
|
||||
]), [
|
||||
'permissions' => request()->has('permissions') ? request('permissions') : [],
|
||||
]);
|
||||
|
||||
$role = $this->roleRepository->update($data, $id);
|
||||
|
||||
Event::dispatch('settings.role.update.after', $role);
|
||||
|
||||
session()->flash('success', trans('admin::app.settings.roles.index.update-success'));
|
||||
|
||||
return redirect()->back();
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*/
|
||||
public function destroy(int $id): JsonResponse
|
||||
{
|
||||
$response = [
|
||||
'responseCode' => 400,
|
||||
];
|
||||
|
||||
$role = $this->roleRepository->findOrFail($id);
|
||||
|
||||
if ($role->users && $role->users->count() >= 1) {
|
||||
$response['message'] = trans('admin::app.settings.roles.index.being-used');
|
||||
|
||||
session()->flash('error', $response['message']);
|
||||
} elseif ($this->roleRepository->count() == 1) {
|
||||
$response['message'] = trans('admin::app.settings.roles.index.last-delete-error');
|
||||
|
||||
session()->flash('error', $response['message']);
|
||||
} else {
|
||||
try {
|
||||
Event::dispatch('settings.role.delete.before', $id);
|
||||
|
||||
if (auth()->guard('user')->user()->role_id == $id) {
|
||||
$response['message'] = trans('admin::app.settings.roles.index.current-role-delete-error');
|
||||
} else {
|
||||
$this->roleRepository->delete($id);
|
||||
|
||||
Event::dispatch('settings.role.delete.after', $id);
|
||||
|
||||
$message = trans('admin::app.settings.roles.index.delete-success');
|
||||
|
||||
$response = [
|
||||
'responseCode' => 200,
|
||||
'message' => $message,
|
||||
];
|
||||
|
||||
session()->flash('success', $message);
|
||||
}
|
||||
} catch (\Exception $exception) {
|
||||
$message = $exception->getMessage();
|
||||
|
||||
$response['message'] = $message;
|
||||
|
||||
session()->flash('error', $message);
|
||||
}
|
||||
}
|
||||
|
||||
return response()->json($response, $response['responseCode']);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Admin\Http\Controllers\Settings;
|
||||
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Support\Collection;
|
||||
use Webkul\Admin\Http\Controllers\Controller;
|
||||
use Webkul\Core\Menu\MenuItem;
|
||||
|
||||
class SettingController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*
|
||||
* @return \Illuminate\View\View
|
||||
*/
|
||||
public function index()
|
||||
{
|
||||
return view('admin::settings.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for settings.
|
||||
*/
|
||||
public function search(): ?JsonResponse
|
||||
{
|
||||
$query = strtolower(request()->query('query'));
|
||||
|
||||
if (empty($query)) {
|
||||
return response()->json(['data' => []]);
|
||||
}
|
||||
|
||||
$results = $this->searchMenuItems($this->getSettingsConfig(), $query);
|
||||
|
||||
return response()->json([
|
||||
'data' => $results->values(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively search through menu items and children.
|
||||
*
|
||||
* @param Collection<int, MenuItem> $menuItems
|
||||
* @return Collection<int, array<string, mixed>>
|
||||
*/
|
||||
protected function searchMenuItems(Collection $menuItems, string $query): Collection
|
||||
{
|
||||
$results = collect();
|
||||
|
||||
foreach ($menuItems as $item) {
|
||||
if ($this->matchesQuery($item, $query)) {
|
||||
$results->push([
|
||||
'name' => $item->getName(),
|
||||
'url' => $item->getUrl(),
|
||||
'icon' => $item->getIcon(),
|
||||
'key' => $item->getKey(),
|
||||
]);
|
||||
}
|
||||
|
||||
if ($item->haveChildren()) {
|
||||
$childResults = $this->searchMenuItems($item->getChildren(), $query);
|
||||
|
||||
$results = $results->merge($childResults);
|
||||
}
|
||||
}
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the menu item matches the query.
|
||||
*/
|
||||
protected function matchesQuery(MenuItem $item, string $query): bool
|
||||
{
|
||||
$query = strtolower($query);
|
||||
$url = strtolower($item->getUrl());
|
||||
|
||||
if (
|
||||
! $url
|
||||
|| ! str_contains($url, $query)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the settings configuration.
|
||||
*/
|
||||
protected function getSettingsConfig(): Collection
|
||||
{
|
||||
return menu()
|
||||
->getItems('admin')
|
||||
->filter(fn (MenuItem $item) => $item->getKey() === 'settings');
|
||||
}
|
||||
}
|
||||
117
packages/Webkul/Admin/src/Http/Controllers/Settings/SourceController.php
Executable file
117
packages/Webkul/Admin/src/Http/Controllers/Settings/SourceController.php
Executable file
@@ -0,0 +1,117 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Admin\Http\Controllers\Settings;
|
||||
|
||||
use Exception;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Support\Facades\Event;
|
||||
use Illuminate\View\View;
|
||||
use Webkul\Admin\DataGrids\Settings\SourceDataGrid;
|
||||
use Webkul\Admin\Http\Controllers\Controller;
|
||||
use Webkul\Lead\Repositories\SourceRepository;
|
||||
|
||||
class SourceController extends Controller
|
||||
{
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(protected SourceRepository $sourceRepository) {}
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*/
|
||||
public function index(): View|JsonResponse
|
||||
{
|
||||
if (request()->ajax()) {
|
||||
return datagrid(SourceDataGrid::class)->process();
|
||||
}
|
||||
|
||||
return view('admin::settings.sources.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*/
|
||||
public function store(): JsonResponse
|
||||
{
|
||||
$this->validate(request(), [
|
||||
'name' => ['required', 'unique:lead_sources,name'],
|
||||
]);
|
||||
|
||||
Event::dispatch('settings.source.create.before');
|
||||
|
||||
$source = $this->sourceRepository->create(request()->only(['name']));
|
||||
|
||||
Event::dispatch('settings.source.create.after', $source);
|
||||
|
||||
return new JsonResponse([
|
||||
'data' => $source,
|
||||
'message' => trans('admin::app.settings.sources.index.create-success'),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*/
|
||||
public function edit(int $id): View|JsonResponse
|
||||
{
|
||||
$source = $this->sourceRepository->findOrFail($id);
|
||||
|
||||
return new JsonResponse([
|
||||
'data' => $source,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*/
|
||||
public function update(int $id): JsonResponse
|
||||
{
|
||||
$this->validate(request(), [
|
||||
'name' => 'required|unique:lead_sources,name,'.$id,
|
||||
]);
|
||||
|
||||
Event::dispatch('settings.source.update.before', $id);
|
||||
|
||||
$source = $this->sourceRepository->update(request()->only(['name']), $id);
|
||||
|
||||
Event::dispatch('settings.source.update.after', $source);
|
||||
|
||||
return new JsonResponse([
|
||||
'data' => $source,
|
||||
'message' => trans('admin::app.settings.sources.index.update-success'),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*/
|
||||
public function destroy(int $id): JsonResponse
|
||||
{
|
||||
$source = $this->sourceRepository->findOrFail($id);
|
||||
|
||||
if ($source->leads()->count() > 0) {
|
||||
return new JsonResponse([
|
||||
'message' => trans('admin::app.settings.sources.index.delete-failed-associated-leads'),
|
||||
], 400);
|
||||
}
|
||||
|
||||
try {
|
||||
Event::dispatch('settings.source.delete.before', $id);
|
||||
|
||||
$source->delete();
|
||||
|
||||
Event::dispatch('settings.source.delete.after', $id);
|
||||
|
||||
return new JsonResponse([
|
||||
'message' => trans('admin::app.settings.sources.index.delete-success'),
|
||||
], 200);
|
||||
} catch (Exception $exception) {
|
||||
return new JsonResponse([
|
||||
'message' => trans('admin::app.settings.sources.index.delete-failed'),
|
||||
], 400);
|
||||
}
|
||||
}
|
||||
}
|
||||
161
packages/Webkul/Admin/src/Http/Controllers/Settings/TagController.php
Executable file
161
packages/Webkul/Admin/src/Http/Controllers/Settings/TagController.php
Executable file
@@ -0,0 +1,161 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Admin\Http\Controllers\Settings;
|
||||
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Support\Facades\Event;
|
||||
use Illuminate\View\View;
|
||||
use Prettus\Repository\Criteria\RequestCriteria;
|
||||
use Webkul\Admin\DataGrids\Settings\TagDataGrid;
|
||||
use Webkul\Admin\Http\Controllers\Controller;
|
||||
use Webkul\Admin\Http\Requests\MassDestroyRequest;
|
||||
use Webkul\Admin\Http\Resources\TagResource;
|
||||
use Webkul\Tag\Repositories\TagRepository;
|
||||
|
||||
class TagController extends Controller
|
||||
{
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(protected TagRepository $tagRepository) {}
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*/
|
||||
public function index(): View|JsonResponse
|
||||
{
|
||||
if (request()->ajax()) {
|
||||
return datagrid(TagDataGrid::class)->process();
|
||||
}
|
||||
|
||||
return view('admin::settings.tags.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*/
|
||||
public function store(): JsonResponse
|
||||
{
|
||||
$this->validate(request(), [
|
||||
'name' => ['required', 'unique:tags,name', 'max:50'],
|
||||
]);
|
||||
|
||||
Event::dispatch('settings.tag.create.before');
|
||||
|
||||
$tag = $this->tagRepository->create(array_merge(request()->only([
|
||||
'name',
|
||||
'color',
|
||||
]), [
|
||||
'user_id' => auth()->guard('user')->user()->id,
|
||||
]));
|
||||
|
||||
Event::dispatch('settings.tag.create.after', $tag);
|
||||
|
||||
return new JsonResponse([
|
||||
'data' => new TagResource($tag),
|
||||
'message' => trans('admin::app.settings.tags.index.create-success'),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified tag.
|
||||
*/
|
||||
public function edit(int $id): View|JsonResponse
|
||||
{
|
||||
$tag = $this->tagRepository->findOrFail($id);
|
||||
|
||||
return new JsonResponse([
|
||||
'data' => $tag,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified tag in storage.
|
||||
*/
|
||||
public function update(int $id): JsonResponse
|
||||
{
|
||||
$this->validate(request(), [
|
||||
'name' => 'required|max:50|unique:tags,name,'.$id,
|
||||
]);
|
||||
|
||||
Event::dispatch('settings.tag.update.before', $id);
|
||||
|
||||
$tag = $this->tagRepository->update(request()->only([
|
||||
'name',
|
||||
'color',
|
||||
]), $id);
|
||||
|
||||
Event::dispatch('settings.tag.update.after', $tag);
|
||||
|
||||
return new JsonResponse([
|
||||
'data' => new TagResource($tag),
|
||||
'message' => trans('admin::app.settings.tags.index.update-success'),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified type from storage.
|
||||
*/
|
||||
public function destroy(int $id): JsonResponse
|
||||
{
|
||||
$tag = $this->tagRepository->findOrFail($id);
|
||||
|
||||
try {
|
||||
Event::dispatch('settings.tag.delete.before', $id);
|
||||
|
||||
$tag->delete($id);
|
||||
|
||||
Event::dispatch('settings.tag.delete.after', $id);
|
||||
|
||||
return new JsonResponse([
|
||||
'message' => trans('admin::app.settings.tags.index.delete-success'),
|
||||
], 200);
|
||||
} catch (\Exception $exception) {
|
||||
return new JsonResponse([
|
||||
'message' => trans('admin::app.settings.tags.index.delete-failed'),
|
||||
], 400);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Search tag results
|
||||
*
|
||||
* @return \Illuminate\Http\Response
|
||||
*/
|
||||
public function search()
|
||||
{
|
||||
$tags = $this->tagRepository
|
||||
->pushCriteria(app(RequestCriteria::class))
|
||||
->all();
|
||||
|
||||
return TagResource::collection($tags);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mass Delete the specified resources.
|
||||
*/
|
||||
public function massDestroy(MassDestroyRequest $massDestroyRequest): JsonResponse
|
||||
{
|
||||
$indices = $massDestroyRequest->input('indices');
|
||||
|
||||
try {
|
||||
foreach ($indices as $index) {
|
||||
Event::dispatch('settings.tag.delete.before', $index);
|
||||
|
||||
$this->tagRepository->delete($index);
|
||||
|
||||
Event::dispatch('settings.tag.delete.after', $index);
|
||||
}
|
||||
|
||||
return new JsonResponse([
|
||||
'message' => trans('admin::app.customers.reviews.index.datagrid.mass-delete-success'),
|
||||
], 200);
|
||||
} catch (\Exception $e) {
|
||||
return new JsonResponse([
|
||||
'message' => $e->getMessage(),
|
||||
], 500);
|
||||
}
|
||||
}
|
||||
}
|
||||
110
packages/Webkul/Admin/src/Http/Controllers/Settings/TypeController.php
Executable file
110
packages/Webkul/Admin/src/Http/Controllers/Settings/TypeController.php
Executable file
@@ -0,0 +1,110 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Admin\Http\Controllers\Settings;
|
||||
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Support\Facades\Event;
|
||||
use Illuminate\View\View;
|
||||
use Webkul\Admin\DataGrids\Settings\TypeDataGrid;
|
||||
use Webkul\Admin\Http\Controllers\Controller;
|
||||
use Webkul\Lead\Repositories\TypeRepository;
|
||||
|
||||
class TypeController extends Controller
|
||||
{
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(protected TypeRepository $typeRepository) {}
|
||||
|
||||
/**
|
||||
* Display a listing of the type.
|
||||
*/
|
||||
public function index(): View|JsonResponse
|
||||
{
|
||||
if (request()->ajax()) {
|
||||
return datagrid(TypeDataGrid::class)->process();
|
||||
}
|
||||
|
||||
return view('admin::settings.types.index');
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created type in storage.
|
||||
*/
|
||||
public function store(): JsonResponse
|
||||
{
|
||||
$this->validate(request(), [
|
||||
'name' => ['required', 'unique:lead_types,name'],
|
||||
]);
|
||||
|
||||
Event::dispatch('settings.type.create.before');
|
||||
|
||||
$type = $this->typeRepository->create(request()->only(['name']));
|
||||
|
||||
Event::dispatch('settings.type.create.after', $type);
|
||||
|
||||
return new JsonResponse([
|
||||
'data' => $type,
|
||||
'message' => trans('admin::app.settings.types.index.create-success'),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified type.
|
||||
*/
|
||||
public function edit(int $id): View|JsonResponse
|
||||
{
|
||||
$type = $this->typeRepository->findOrFail($id);
|
||||
|
||||
return new JsonResponse([
|
||||
'data' => $type,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified type in storage.
|
||||
*/
|
||||
public function update(int $id): JsonResponse
|
||||
{
|
||||
$this->validate(request(), [
|
||||
'name' => 'required|unique:lead_types,name,'.$id,
|
||||
]);
|
||||
|
||||
Event::dispatch('settings.type.update.before', $id);
|
||||
|
||||
$type = $this->typeRepository->update(request()->only(['name']), $id);
|
||||
|
||||
Event::dispatch('settings.type.update.after', $type);
|
||||
|
||||
return new JsonResponse([
|
||||
'data' => $type,
|
||||
'message' => trans('admin::app.settings.types.index.update-success'),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified type from storage.
|
||||
*/
|
||||
public function destroy(int $id): JsonResponse
|
||||
{
|
||||
$type = $this->typeRepository->findOrFail($id);
|
||||
|
||||
try {
|
||||
Event::dispatch('settings.type.delete.before', $id);
|
||||
|
||||
$type->delete($id);
|
||||
|
||||
Event::dispatch('settings.type.delete.after', $id);
|
||||
|
||||
return new JsonResponse([
|
||||
'message' => trans('admin::app.settings.types.index.delete-success'),
|
||||
], 200);
|
||||
} catch (\Exception $exception) {
|
||||
return new JsonResponse([
|
||||
'message' => trans('admin::app.settings.types.index.delete-failed'),
|
||||
], 400);
|
||||
}
|
||||
}
|
||||
}
|
||||
260
packages/Webkul/Admin/src/Http/Controllers/Settings/UserController.php
Executable file
260
packages/Webkul/Admin/src/Http/Controllers/Settings/UserController.php
Executable file
@@ -0,0 +1,260 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Admin\Http\Controllers\Settings;
|
||||
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Facades\Event;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use Illuminate\View\View;
|
||||
use Prettus\Repository\Criteria\RequestCriteria;
|
||||
use Webkul\Admin\DataGrids\Settings\UserDataGrid;
|
||||
use Webkul\Admin\Http\Controllers\Controller;
|
||||
use Webkul\Admin\Http\Requests\MassDestroyRequest;
|
||||
use Webkul\Admin\Http\Requests\MassUpdateRequest;
|
||||
use Webkul\Admin\Http\Resources\UserResource;
|
||||
use Webkul\Admin\Notifications\User\Create as UserCreatedNotification;
|
||||
use Webkul\User\Repositories\GroupRepository;
|
||||
use Webkul\User\Repositories\RoleRepository;
|
||||
use Webkul\User\Repositories\UserRepository;
|
||||
|
||||
class UserController extends Controller
|
||||
{
|
||||
/**
|
||||
* Create a new controller instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(
|
||||
protected UserRepository $userRepository,
|
||||
protected GroupRepository $groupRepository,
|
||||
protected RoleRepository $roleRepository
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*/
|
||||
public function index(): View|JsonResponse
|
||||
{
|
||||
if (request()->ajax()) {
|
||||
return datagrid(UserDataGrid::class)->process();
|
||||
}
|
||||
|
||||
$roles = $this->roleRepository->all();
|
||||
|
||||
$groups = $this->groupRepository->all();
|
||||
|
||||
return view('admin::settings.users.index', compact('roles', 'groups'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*/
|
||||
public function store(): View|JsonResponse
|
||||
{
|
||||
$this->validate(request(), [
|
||||
'email' => 'required|email|unique:users,email',
|
||||
'name' => 'required',
|
||||
'password' => 'nullable',
|
||||
'confirm_password' => 'nullable|required_with:password|same:password',
|
||||
'role_id' => 'required',
|
||||
'status' => 'boolean|in:0,1',
|
||||
'view_permission' => 'string|in:global,group,individual',
|
||||
]);
|
||||
|
||||
$data = request()->all();
|
||||
|
||||
if (
|
||||
isset($data['password'])
|
||||
&& $data['password']
|
||||
) {
|
||||
$data['password'] = bcrypt($data['password']);
|
||||
}
|
||||
|
||||
Event::dispatch('settings.user.create.before');
|
||||
|
||||
$admin = $this->userRepository->create($data);
|
||||
|
||||
$admin->groups()->sync($data['groups'] ?? []);
|
||||
|
||||
try {
|
||||
Mail::queue(new UserCreatedNotification($admin));
|
||||
} catch (\Exception $e) {
|
||||
report($e);
|
||||
}
|
||||
|
||||
Event::dispatch('settings.user.create.after', $admin);
|
||||
|
||||
return new JsonResponse([
|
||||
'data' => $admin,
|
||||
'message' => trans('admin::app.settings.users.index.create-success'),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*/
|
||||
public function edit(int $id): View|JsonResponse
|
||||
{
|
||||
$admin = $this->userRepository->with(['role', 'groups'])->findOrFail($id);
|
||||
|
||||
return new JsonResponse([
|
||||
'data' => $admin,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*/
|
||||
public function update(int $id): JsonResponse
|
||||
{
|
||||
$this->validate(request(), [
|
||||
'email' => 'required|email|unique:users,email,'.$id,
|
||||
'name' => 'required|string',
|
||||
'password' => 'nullable|string|min:6',
|
||||
'confirm_password' => 'nullable|required_with:password|same:password',
|
||||
'role_id' => 'required|integer|exists:roles,id',
|
||||
'status' => 'nullable|boolean|in:0,1',
|
||||
'view_permission' => 'required|string|in:global,group,individual',
|
||||
]);
|
||||
|
||||
$data = request()->all();
|
||||
|
||||
if (empty($data['password'])) {
|
||||
$data = Arr::except($data, ['password', 'confirm_password']);
|
||||
} else {
|
||||
$data['password'] = bcrypt($data['password']);
|
||||
}
|
||||
|
||||
$authUser = auth()->guard('user')->user();
|
||||
|
||||
if ($authUser->id == $id) {
|
||||
$data['status'] = true;
|
||||
}
|
||||
|
||||
Event::dispatch('settings.user.update.before', $id);
|
||||
|
||||
$admin = $this->userRepository->update($data, $id);
|
||||
|
||||
$admin->groups()->sync($data['groups'] ?? []);
|
||||
|
||||
Event::dispatch('settings.user.update.after', $admin);
|
||||
|
||||
return new JsonResponse([
|
||||
'data' => $admin,
|
||||
'message' => trans('admin::app.settings.users.index.update-success'),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Search user results.
|
||||
*/
|
||||
public function search(): JsonResource
|
||||
{
|
||||
$users = $this->userRepository
|
||||
->pushCriteria(app(RequestCriteria::class))
|
||||
->all();
|
||||
|
||||
return UserResource::collection($users);
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy specified user.
|
||||
*/
|
||||
public function destroy(int $id): JsonResponse
|
||||
{
|
||||
if ($this->userRepository->count() == 1) {
|
||||
return new JsonResponse([
|
||||
'message' => trans('admin::app.settings.users.index.last-delete-error'),
|
||||
], 400);
|
||||
}
|
||||
|
||||
try {
|
||||
Event::dispatch('user.admin.delete.before', $id);
|
||||
|
||||
$this->userRepository->delete($id);
|
||||
|
||||
Event::dispatch('user.admin.delete.after', $id);
|
||||
|
||||
return new JsonResponse([
|
||||
'message' => trans('admin::app.settings.users.index.delete-success'),
|
||||
], 200);
|
||||
} catch (\Exception $e) {
|
||||
}
|
||||
|
||||
return new JsonResponse([
|
||||
'message' => trans('admin::app.settings.users.index.delete-failed'),
|
||||
], 500);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mass Update the specified resources.
|
||||
*/
|
||||
public function massUpdate(MassUpdateRequest $massDestroyRequest): JsonResponse
|
||||
{
|
||||
$count = 0;
|
||||
|
||||
$users = $this->userRepository->findWhereIn('id', $massDestroyRequest->input('indices'));
|
||||
|
||||
foreach ($users as $users) {
|
||||
if (auth()->guard('user')->user()->id == $users->id) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Event::dispatch('settings.user.update.before', $users->id);
|
||||
|
||||
$this->userRepository->update([
|
||||
'status' => $massDestroyRequest->input('value'),
|
||||
], $users->id);
|
||||
|
||||
Event::dispatch('settings.user.update.after', $users->id);
|
||||
|
||||
$count++;
|
||||
}
|
||||
|
||||
if (! $count) {
|
||||
return response()->json([
|
||||
'message' => trans('admin::app.settings.users.index.mass-update-failed'),
|
||||
], 400);
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'message' => trans('admin::app.settings.users.index.mass-update-success'),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mass Delete the specified resources.
|
||||
*/
|
||||
public function massDestroy(MassDestroyRequest $massDestroyRequest): JsonResponse
|
||||
{
|
||||
$count = 0;
|
||||
|
||||
$users = $this->userRepository->findWhereIn('id', $massDestroyRequest->input('indices'));
|
||||
|
||||
foreach ($users as $user) {
|
||||
if (auth()->guard('user')->user()->id == $user->id) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Event::dispatch('settings.user.delete.before', $user->id);
|
||||
|
||||
$this->userRepository->delete($user->id);
|
||||
|
||||
Event::dispatch('settings.user.delete.after', $user->id);
|
||||
|
||||
$count++;
|
||||
}
|
||||
|
||||
if (! $count) {
|
||||
return response()->json([
|
||||
'message' => trans('admin::app.settings.users.index.mass-delete-failed'),
|
||||
], 400);
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'message' => trans('admin::app.settings.users.index.mass-delete-success'),
|
||||
]);
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user