add: full multi-tenancy control
This commit is contained in:
35
packages/Webkul/Lead/composer.json
Executable file
35
packages/Webkul/Lead/composer.json
Executable file
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"name": "krayin/laravel-lead",
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Jitendra Singh",
|
||||
"email": "jitendra@webkul.com"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"krayin/laravel-activity": "^1.0",
|
||||
"krayin/laravel-attribute": "^1.0",
|
||||
"krayin/laravel-contact": "^1.0",
|
||||
"krayin/laravel-core": "^1.0",
|
||||
"krayin/laravel-email": "^1.0",
|
||||
"krayin/laravel-product": "^1.0",
|
||||
"krayin/laravel-quote": "^1.0",
|
||||
"krayin/laravel-tag": "^1.0",
|
||||
"krayin/laravel-user": "^1.0"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Webkul\\Lead\\": "src/"
|
||||
}
|
||||
},
|
||||
"extra": {
|
||||
"laravel": {
|
||||
"providers": [
|
||||
"Webkul\\Lead\\Providers\\LeadServiceProvider"
|
||||
],
|
||||
"aliases": {}
|
||||
}
|
||||
},
|
||||
"minimum-stability": "dev"
|
||||
}
|
||||
5
packages/Webkul/Lead/src/Contracts/Lead.php
Normal file
5
packages/Webkul/Lead/src/Contracts/Lead.php
Normal file
@@ -0,0 +1,5 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Lead\Contracts;
|
||||
|
||||
interface Lead {}
|
||||
5
packages/Webkul/Lead/src/Contracts/Pipeline.php
Normal file
5
packages/Webkul/Lead/src/Contracts/Pipeline.php
Normal file
@@ -0,0 +1,5 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Lead\Contracts;
|
||||
|
||||
interface Pipeline {}
|
||||
5
packages/Webkul/Lead/src/Contracts/Product.php
Normal file
5
packages/Webkul/Lead/src/Contracts/Product.php
Normal file
@@ -0,0 +1,5 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Lead\Contracts;
|
||||
|
||||
interface Product {}
|
||||
5
packages/Webkul/Lead/src/Contracts/Source.php
Normal file
5
packages/Webkul/Lead/src/Contracts/Source.php
Normal file
@@ -0,0 +1,5 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Lead\Contracts;
|
||||
|
||||
interface Source {}
|
||||
5
packages/Webkul/Lead/src/Contracts/Stage.php
Normal file
5
packages/Webkul/Lead/src/Contracts/Stage.php
Normal file
@@ -0,0 +1,5 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Lead\Contracts;
|
||||
|
||||
interface Stage {}
|
||||
5
packages/Webkul/Lead/src/Contracts/Type.php
Normal file
5
packages/Webkul/Lead/src/Contracts/Type.php
Normal file
@@ -0,0 +1,5 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Lead\Contracts;
|
||||
|
||||
interface Type {}
|
||||
@@ -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::create('lead_sources', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->string('name');
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('lead_sources');
|
||||
}
|
||||
};
|
||||
@@ -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::create('lead_types', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->string('name');
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('lead_types');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,34 @@
|
||||
<?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('lead_stages', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->string('code');
|
||||
$table->string('name');
|
||||
$table->boolean('is_user_defined')->default(1);
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('lead_stages');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,33 @@
|
||||
<?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('lead_pipelines', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->string('name');
|
||||
$table->boolean('is_default')->default(0);
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('lead_pipelines');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,38 @@
|
||||
<?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('lead_pipeline_stages', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->integer('probability')->default(0);
|
||||
$table->integer('sort_order')->default(0);
|
||||
|
||||
$table->integer('lead_stage_id')->unsigned();
|
||||
$table->foreign('lead_stage_id')->references('id')->on('lead_stages')->onDelete('cascade');
|
||||
|
||||
$table->integer('lead_pipeline_id')->unsigned();
|
||||
$table->foreign('lead_pipeline_id')->references('id')->on('lead_pipelines')->onDelete('cascade');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('lead_pipeline_stages');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,56 @@
|
||||
<?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('leads', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->string('title');
|
||||
$table->text('description')->nullable();
|
||||
$table->decimal('lead_value', 12, 4)->nullable();
|
||||
$table->boolean('status')->nullable();
|
||||
$table->text('lost_reason')->nullable();
|
||||
$table->datetime('closed_at')->nullable();
|
||||
|
||||
$table->integer('user_id')->unsigned();
|
||||
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
|
||||
|
||||
$table->integer('person_id')->unsigned();
|
||||
$table->foreign('person_id')->references('id')->on('persons')->onDelete('cascade');
|
||||
|
||||
$table->integer('lead_source_id')->unsigned();
|
||||
$table->foreign('lead_source_id')->references('id')->on('lead_sources')->onDelete('cascade');
|
||||
|
||||
$table->integer('lead_type_id')->unsigned();
|
||||
$table->foreign('lead_type_id')->references('id')->on('lead_types')->onDelete('cascade');
|
||||
|
||||
$table->integer('lead_pipeline_id')->unsigned()->nullable();
|
||||
$table->foreign('lead_pipeline_id')->references('id')->on('lead_pipelines')->onDelete('cascade');
|
||||
|
||||
$table->integer('lead_stage_id')->unsigned();
|
||||
$table->foreign('lead_stage_id')->references('id')->on('lead_stages')->onDelete('cascade');
|
||||
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('leads');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,40 @@
|
||||
<?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('lead_products', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->integer('quantity')->default(0);
|
||||
$table->decimal('price', 12, 4)->nullable();
|
||||
$table->decimal('amount', 12, 4)->nullable();
|
||||
|
||||
$table->integer('lead_id')->unsigned();
|
||||
$table->foreign('lead_id')->references('id')->on('leads')->onDelete('cascade');
|
||||
|
||||
$table->integer('product_id')->unsigned();
|
||||
$table->foreign('product_id')->references('id')->on('products')->onDelete('cascade');
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('lead_products');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,34 @@
|
||||
<?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('lead_activities', function (Blueprint $table) {
|
||||
$table->integer('activity_id')->unsigned();
|
||||
$table->foreign('activity_id')->references('id')->on('activities')->onDelete('cascade');
|
||||
|
||||
$table->integer('lead_id')->unsigned();
|
||||
$table->foreign('lead_id')->references('id')->on('leads')->onDelete('cascade');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('lead_activities');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,34 @@
|
||||
<?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('lead_tags', function (Blueprint $table) {
|
||||
$table->integer('tag_id')->unsigned();
|
||||
$table->foreign('tag_id')->references('id')->on('tags')->onDelete('cascade');
|
||||
|
||||
$table->integer('lead_id')->unsigned();
|
||||
$table->foreign('lead_id')->references('id')->on('leads')->onDelete('cascade');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('lead_tags');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,34 @@
|
||||
<?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('lead_quotes', function (Blueprint $table) {
|
||||
$table->integer('quote_id')->unsigned();
|
||||
$table->foreign('quote_id')->references('id')->on('quotes')->onDelete('cascade');
|
||||
|
||||
$table->integer('lead_id')->unsigned();
|
||||
$table->foreign('lead_id')->references('id')->on('leads')->onDelete('cascade');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('lead_quotes');
|
||||
}
|
||||
};
|
||||
@@ -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('leads', function (Blueprint $table) {
|
||||
$table->date('expected_close_date')->nullable();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('leads', function (Blueprint $table) {
|
||||
$table->dropColumn('expected_close_date');
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -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('lead_pipelines', function (Blueprint $table) {
|
||||
$table->integer('rotten_days')->after('is_default')->default(30);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('lead_pipelines', function (Blueprint $table) {
|
||||
$table->dropColumn('rotten_days');
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,57 @@
|
||||
<?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()
|
||||
{
|
||||
$tablePrefix = DB::getTablePrefix();
|
||||
|
||||
Schema::table('lead_pipeline_stages', function (Blueprint $table) {
|
||||
$table->string('code')->after('id')->nullable();
|
||||
$table->string('name')->after('code')->nullable();
|
||||
});
|
||||
|
||||
DB::table('lead_pipeline_stages')
|
||||
->join('lead_stages', 'lead_pipeline_stages.lead_stage_id', '=', 'lead_stages.id')
|
||||
->update([
|
||||
'lead_pipeline_stages.code' => DB::raw($tablePrefix.'lead_stages.code'),
|
||||
'lead_pipeline_stages.name' => DB::raw($tablePrefix.'lead_stages.name'),
|
||||
]);
|
||||
|
||||
Schema::table('lead_pipeline_stages', function (Blueprint $table) use ($tablePrefix) {
|
||||
$table->dropForeign($tablePrefix.'lead_pipeline_stages_lead_stage_id_foreign');
|
||||
$table->dropColumn('lead_stage_id');
|
||||
|
||||
$table->unique(['code', 'lead_pipeline_id']);
|
||||
$table->unique(['name', 'lead_pipeline_id']);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('lead_pipeline_stages', function (Blueprint $table) {
|
||||
$table->dropColumn('code');
|
||||
$table->dropColumn('name');
|
||||
|
||||
$table->integer('lead_stage_id')->unsigned();
|
||||
$table->foreign('lead_stage_id')->references('id')->on('lead_stages')->onDelete('cascade');
|
||||
|
||||
$table->dropUnique(['lead_pipeline_stages_code_lead_pipeline_id_unique', 'lead_pipeline_stages_name_lead_pipeline_id_unique']);
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,50 @@
|
||||
<?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()
|
||||
{
|
||||
$tablePrefix = DB::getTablePrefix();
|
||||
|
||||
Schema::table('leads', function (Blueprint $table) {
|
||||
$table->integer('lead_pipeline_stage_id')->after('lead_pipeline_id')->unsigned()->nullable();
|
||||
$table->foreign('lead_pipeline_stage_id')->references('id')->on('lead_pipeline_stages')->onDelete('cascade');
|
||||
});
|
||||
|
||||
DB::table('leads')
|
||||
->update([
|
||||
'leads.lead_pipeline_stage_id' => DB::raw($tablePrefix.'leads.lead_stage_id'),
|
||||
]);
|
||||
|
||||
Schema::table('leads', function (Blueprint $table) use ($tablePrefix) {
|
||||
$table->dropForeign($tablePrefix.'leads_lead_stage_id_foreign');
|
||||
$table->dropColumn('lead_stage_id');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('leads', function (Blueprint $table) {
|
||||
$table->dropForeign(DB::getTablePrefix().'leads_lead_pipeline_stage_id_foreign');
|
||||
$table->dropColumn('lead_pipeline_stage_id');
|
||||
|
||||
$table->integer('lead_stage_id')->unsigned();
|
||||
$table->foreign('lead_stage_id')->references('id')->on('lead_stages')->onDelete('cascade');
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -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('leads', function (Blueprint $table) {
|
||||
$table->integer('user_id')->unsigned()->nullable()->change();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('leads', function (Blueprint $table) {
|
||||
$table->integer('user_id')->unsigned()->nullable()->change();
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,36 @@
|
||||
<?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('leads', function (Blueprint $table) {
|
||||
$table->dropForeign(['lead_pipeline_stage_id']);
|
||||
|
||||
$table->foreign('lead_pipeline_stage_id')->references('id')->on('lead_pipeline_stages')->onDelete('set null');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('leads', function (Blueprint $table) {
|
||||
$table->dropForeign(['lead_pipeline_stage_id']);
|
||||
|
||||
$table->foreign('lead_pipeline_stage_id')->references('id')->on('lead_pipeline_stages')->onDelete('cascade');
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,80 @@
|
||||
<?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('leads', function (Blueprint $table) {
|
||||
$table->integer('user_id')->unsigned()->nullable()->change();
|
||||
$table->integer('person_id')->unsigned()->nullable()->change();
|
||||
$table->integer('lead_source_id')->unsigned()->nullable()->change();
|
||||
$table->integer('lead_type_id')->unsigned()->nullable()->change();
|
||||
|
||||
$table->dropForeign(['user_id']);
|
||||
$table->dropForeign(['person_id']);
|
||||
$table->dropForeign(['lead_source_id']);
|
||||
$table->dropForeign(['lead_type_id']);
|
||||
|
||||
$table->foreign('user_id')
|
||||
->references('id')->on('users')
|
||||
->onDelete('set null');
|
||||
|
||||
$table->foreign('person_id')
|
||||
->references('id')->on('persons')
|
||||
->onDelete('restrict');
|
||||
|
||||
$table->foreign('lead_source_id')
|
||||
->references('id')->on('lead_sources')
|
||||
->onDelete('restrict');
|
||||
|
||||
$table->foreign('lead_type_id')
|
||||
->references('id')->on('lead_types')
|
||||
->onDelete('restrict');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('leads', function (Blueprint $table) {
|
||||
$table->dropForeign(['user_id']);
|
||||
$table->dropForeign(['person_id']);
|
||||
$table->dropForeign(['lead_source_id']);
|
||||
$table->dropForeign(['lead_type_id']);
|
||||
|
||||
$table->integer('user_id')->unsigned()->nullable()->change();
|
||||
$table->integer('person_id')->unsigned()->nullable(false)->change();
|
||||
$table->integer('lead_source_id')->unsigned()->nullable(false)->change();
|
||||
$table->integer('lead_type_id')->unsigned()->nullable(false)->change();
|
||||
|
||||
$table->foreign('user_id')
|
||||
->references('id')->on('users')
|
||||
->onDelete('cascade');
|
||||
|
||||
$table->foreign('person_id')
|
||||
->references('id')->on('persons')
|
||||
->onDelete('cascade');
|
||||
|
||||
$table->foreign('lead_source_id')
|
||||
->references('id')->on('lead_sources')
|
||||
->onDelete('cascade');
|
||||
|
||||
$table->foreign('lead_type_id')
|
||||
->references('id')->on('lead_types')
|
||||
->onDelete('cascade');
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
return new class extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::table('lead_pipelines', function (Blueprint $table) {
|
||||
$table->string('name')->unique()->change();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::table('lead_pipelines', function (Blueprint $table) {
|
||||
$table->dropUnique(['name']);
|
||||
|
||||
$table->string('name')->change();
|
||||
});
|
||||
}
|
||||
};
|
||||
127
packages/Webkul/Lead/src/Helpers/MagicAI.php
Normal file
127
packages/Webkul/Lead/src/Helpers/MagicAI.php
Normal file
@@ -0,0 +1,127 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Lead\Helpers;
|
||||
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Webkul\Admin\Http\Requests\LeadForm;
|
||||
|
||||
class MagicAI
|
||||
{
|
||||
/**
|
||||
* Const Variable of LEAD_ENTITY.
|
||||
*/
|
||||
const LEAD_ENTITY = 'leads';
|
||||
|
||||
/**
|
||||
* Const Variable of PERSON_ENTITY.
|
||||
*/
|
||||
const PERSON_ENTITY = 'persons';
|
||||
|
||||
/**
|
||||
* Mapped the receive Extracted AI data.
|
||||
*/
|
||||
public static function mapAIDataToLead($aiData)
|
||||
{
|
||||
if (! empty($aiData['error'])) {
|
||||
return self::errorHandler($aiData['error']);
|
||||
}
|
||||
|
||||
$content = strip_tags($aiData['choices'][0]['message']['content']);
|
||||
|
||||
if (empty($content)) {
|
||||
return self::errorHandler(trans('admin::app.leads.file.data-not-found'));
|
||||
}
|
||||
|
||||
preg_match('/\{.*\}/s', $content, $matches);
|
||||
|
||||
if (isset($matches[0])) {
|
||||
$jsonString = $matches[0];
|
||||
} else {
|
||||
return self::errorHandler(trans('admin::app.leads.file.invalid-response'));
|
||||
}
|
||||
|
||||
$finalData = json_decode($jsonString);
|
||||
|
||||
if (json_last_error() !== JSON_ERROR_NONE) {
|
||||
return self::errorHandler(trans('admin::app.leads.file.invalid-format'));
|
||||
}
|
||||
|
||||
try {
|
||||
self::validateLeadData($finalData);
|
||||
|
||||
$validatedData = app(LeadForm::class)->validated();
|
||||
|
||||
return array_merge($validatedData, self::prepareLeadData($finalData));
|
||||
} catch (\Exception $e) {
|
||||
return self::errorHandler($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the lead data.
|
||||
*/
|
||||
private static function validateLeadData($data)
|
||||
{
|
||||
$dataArray = json_decode(json_encode($data), true);
|
||||
|
||||
$validator = Validator::make($dataArray, [
|
||||
'title' => 'required|string|max:255',
|
||||
'lead_value' => 'required|numeric|min:0',
|
||||
'person.name' => 'required|string|max:255',
|
||||
'person.emails.value' => 'required|email',
|
||||
'person.contact_numbers.value' => 'required|string|max:20',
|
||||
]);
|
||||
|
||||
if ($validator->fails()) {
|
||||
throw new \Illuminate\Validation\ValidationException(
|
||||
$validator,
|
||||
response()->json(self::errorHandler($validator->errors()->getMessages()), 400)
|
||||
);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares the lead prompt data.
|
||||
*/
|
||||
private static function prepareLeadData($finalData)
|
||||
{
|
||||
return [
|
||||
'status' => 1,
|
||||
'title' => $finalData->title ?? 'N/A',
|
||||
'description' => $finalData->description ?? null,
|
||||
'lead_source_id' => 1,
|
||||
'lead_type_id' => 1,
|
||||
'lead_value' => $finalData->lead_value ?? 0,
|
||||
'person' => [
|
||||
'name' => $finalData->person->name ?? 'Unknown',
|
||||
'emails' => [
|
||||
[
|
||||
'value' => $finalData->person->emails->value ?? null,
|
||||
'label' => $finalData->person->emails->label ?? 'work',
|
||||
],
|
||||
],
|
||||
'contact_numbers' => [
|
||||
[
|
||||
'value' => $finalData->person->contact_numbers->value ?? null,
|
||||
'label' => $finalData->person->contact_numbers->label ?? 'work',
|
||||
],
|
||||
],
|
||||
'entity_type' => self::PERSON_ENTITY,
|
||||
],
|
||||
'entity_type' => self::LEAD_ENTITY,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares method for error handler.
|
||||
*/
|
||||
public static function errorHandler($message)
|
||||
{
|
||||
return [
|
||||
'status' => 'error',
|
||||
'message' => $message,
|
||||
];
|
||||
}
|
||||
}
|
||||
173
packages/Webkul/Lead/src/Models/Lead.php
Normal file
173
packages/Webkul/Lead/src/Models/Lead.php
Normal file
@@ -0,0 +1,173 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Lead\Models;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Webkul\Activity\Models\ActivityProxy;
|
||||
use Webkul\Activity\Traits\LogsActivity;
|
||||
use Webkul\Attribute\Traits\CustomAttribute;
|
||||
use Webkul\Contact\Models\PersonProxy;
|
||||
use Webkul\Email\Models\EmailProxy;
|
||||
use Webkul\Lead\Contracts\Lead as LeadContract;
|
||||
use Webkul\Quote\Models\QuoteProxy;
|
||||
use Webkul\Tag\Models\TagProxy;
|
||||
use Webkul\User\Models\UserProxy;
|
||||
|
||||
class Lead extends Model implements LeadContract
|
||||
{
|
||||
use CustomAttribute, LogsActivity;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = [
|
||||
'title',
|
||||
'description',
|
||||
'lead_value',
|
||||
'status',
|
||||
'lost_reason',
|
||||
'expected_close_date',
|
||||
'closed_at',
|
||||
'user_id',
|
||||
'person_id',
|
||||
'lead_source_id',
|
||||
'lead_type_id',
|
||||
'lead_pipeline_id',
|
||||
'lead_pipeline_stage_id',
|
||||
];
|
||||
|
||||
/**
|
||||
* Cast the attributes to their respective types.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $casts = [
|
||||
'closed_at' => 'datetime:D M d, Y H:i A',
|
||||
'expected_close_date' => 'date:D M d, Y',
|
||||
];
|
||||
|
||||
/**
|
||||
* The attributes that are appended.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $appends = [
|
||||
'rotten_days',
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the user that owns the lead.
|
||||
*/
|
||||
public function user(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(UserProxy::modelClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the person that owns the lead.
|
||||
*/
|
||||
public function person(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(PersonProxy::modelClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the type that owns the lead.
|
||||
*/
|
||||
public function type(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(TypeProxy::modelClass(), 'lead_type_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the source that owns the lead.
|
||||
*/
|
||||
public function source(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(SourceProxy::modelClass(), 'lead_source_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the pipeline that owns the lead.
|
||||
*/
|
||||
public function pipeline(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(PipelineProxy::modelClass(), 'lead_pipeline_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the pipeline stage that owns the lead.
|
||||
*/
|
||||
public function stage(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(StageProxy::modelClass(), 'lead_pipeline_stage_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the activities.
|
||||
*/
|
||||
public function activities(): BelongsToMany
|
||||
{
|
||||
return $this->belongsToMany(ActivityProxy::modelClass(), 'lead_activities');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the products.
|
||||
*/
|
||||
public function products(): HasMany
|
||||
{
|
||||
return $this->hasMany(ProductProxy::modelClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the emails.
|
||||
*/
|
||||
public function emails(): HasMany
|
||||
{
|
||||
return $this->hasMany(EmailProxy::modelClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* The quotes that belong to the lead.
|
||||
*/
|
||||
public function quotes(): BelongsToMany
|
||||
{
|
||||
return $this->belongsToMany(QuoteProxy::modelClass(), 'lead_quotes');
|
||||
}
|
||||
|
||||
/**
|
||||
* The tags that belong to the lead.
|
||||
*/
|
||||
public function tags(): BelongsToMany
|
||||
{
|
||||
return $this->belongsToMany(TagProxy::modelClass(), 'lead_tags');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the rotten days
|
||||
*/
|
||||
public function getRottenDaysAttribute()
|
||||
{
|
||||
if (! $this->stage) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (in_array($this->stage->code, ['won', 'lost'])) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (! $this->created_at) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$rottenDate = $this->created_at->addDays($this->pipeline->rotten_days);
|
||||
|
||||
return $rottenDate->diffInDays(Carbon::now(), false);
|
||||
}
|
||||
}
|
||||
7
packages/Webkul/Lead/src/Models/LeadProxy.php
Normal file
7
packages/Webkul/Lead/src/Models/LeadProxy.php
Normal file
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Lead\Models;
|
||||
|
||||
use Konekt\Concord\Proxies\ModelProxy;
|
||||
|
||||
class LeadProxy extends ModelProxy {}
|
||||
38
packages/Webkul/Lead/src/Models/Pipeline.php
Normal file
38
packages/Webkul/Lead/src/Models/Pipeline.php
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Lead\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Webkul\Lead\Contracts\Pipeline as PipelineContract;
|
||||
|
||||
class Pipeline extends Model implements PipelineContract
|
||||
{
|
||||
protected $table = 'lead_pipelines';
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = [
|
||||
'name',
|
||||
'rotten_days',
|
||||
'is_default',
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the leads.
|
||||
*/
|
||||
public function leads()
|
||||
{
|
||||
return $this->hasMany(LeadProxy::modelClass(), 'lead_pipeline_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the stages that owns the pipeline.
|
||||
*/
|
||||
public function stages()
|
||||
{
|
||||
return $this->hasMany(StageProxy::modelClass(), 'lead_pipeline_id')->orderBy('sort_order', 'ASC');
|
||||
}
|
||||
}
|
||||
7
packages/Webkul/Lead/src/Models/PipelineProxy.php
Normal file
7
packages/Webkul/Lead/src/Models/PipelineProxy.php
Normal file
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Lead\Models;
|
||||
|
||||
use Konekt\Concord\Proxies\ModelProxy;
|
||||
|
||||
class PipelineProxy extends ModelProxy {}
|
||||
61
packages/Webkul/Lead/src/Models/Product.php
Normal file
61
packages/Webkul/Lead/src/Models/Product.php
Normal file
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Lead\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Webkul\Lead\Contracts\Product as ProductContract;
|
||||
use Webkul\Product\Models\ProductProxy;
|
||||
|
||||
class Product extends Model implements ProductContract
|
||||
{
|
||||
protected $table = 'lead_products';
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = [
|
||||
'quantity',
|
||||
'price',
|
||||
'amount',
|
||||
'product_id',
|
||||
'lead_id',
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the product owns the lead product.
|
||||
*/
|
||||
public function product()
|
||||
{
|
||||
return $this->belongsTo(ProductProxy::modelClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the lead that owns the lead product.
|
||||
*/
|
||||
public function lead()
|
||||
{
|
||||
return $this->belongsTo(LeadProxy::modelClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the customer full name.
|
||||
*/
|
||||
public function getNameAttribute()
|
||||
{
|
||||
return $this->product->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function toArray()
|
||||
{
|
||||
$array = parent::toArray();
|
||||
|
||||
$array['name'] = $this->name;
|
||||
|
||||
return $array;
|
||||
}
|
||||
}
|
||||
7
packages/Webkul/Lead/src/Models/ProductProxy.php
Normal file
7
packages/Webkul/Lead/src/Models/ProductProxy.php
Normal file
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Lead\Models;
|
||||
|
||||
use Konekt\Concord\Proxies\ModelProxy;
|
||||
|
||||
class ProductProxy extends ModelProxy {}
|
||||
28
packages/Webkul/Lead/src/Models/Source.php
Normal file
28
packages/Webkul/Lead/src/Models/Source.php
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Lead\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Webkul\Lead\Contracts\Source as SourceContract;
|
||||
|
||||
class Source extends Model implements SourceContract
|
||||
{
|
||||
protected $table = 'lead_sources';
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = [
|
||||
'name',
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the leads.
|
||||
*/
|
||||
public function leads()
|
||||
{
|
||||
return $this->hasMany(LeadProxy::modelClass(), 'lead_source_id', 'id');
|
||||
}
|
||||
}
|
||||
7
packages/Webkul/Lead/src/Models/SourceProxy.php
Normal file
7
packages/Webkul/Lead/src/Models/SourceProxy.php
Normal file
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Lead\Models;
|
||||
|
||||
use Konekt\Concord\Proxies\ModelProxy;
|
||||
|
||||
class SourceProxy extends ModelProxy {}
|
||||
42
packages/Webkul/Lead/src/Models/Stage.php
Normal file
42
packages/Webkul/Lead/src/Models/Stage.php
Normal file
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Lead\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Webkul\Lead\Contracts\Stage as StageContract;
|
||||
|
||||
class Stage extends Model implements StageContract
|
||||
{
|
||||
public $timestamps = false;
|
||||
|
||||
protected $table = 'lead_pipeline_stages';
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = [
|
||||
'code',
|
||||
'name',
|
||||
'probability',
|
||||
'sort_order',
|
||||
'lead_pipeline_id',
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the pipeline that owns the pipeline stage.
|
||||
*/
|
||||
public function pipeline()
|
||||
{
|
||||
return $this->belongsTo(PipelineProxy::modelClass(), 'lead_pipeline_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the leads.
|
||||
*/
|
||||
public function leads()
|
||||
{
|
||||
return $this->hasMany(LeadProxy::modelClass(), 'lead_pipeline_stage_id');
|
||||
}
|
||||
}
|
||||
7
packages/Webkul/Lead/src/Models/StageProxy.php
Normal file
7
packages/Webkul/Lead/src/Models/StageProxy.php
Normal file
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Lead\Models;
|
||||
|
||||
use Konekt\Concord\Proxies\ModelProxy;
|
||||
|
||||
class StageProxy extends ModelProxy {}
|
||||
28
packages/Webkul/Lead/src/Models/Type.php
Normal file
28
packages/Webkul/Lead/src/Models/Type.php
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Lead\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Webkul\Lead\Contracts\Type as TypeContract;
|
||||
|
||||
class Type extends Model implements TypeContract
|
||||
{
|
||||
protected $table = 'lead_types';
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $fillable = [
|
||||
'name',
|
||||
];
|
||||
|
||||
/**
|
||||
* Get the leads.
|
||||
*/
|
||||
public function leads()
|
||||
{
|
||||
return $this->hasMany(LeadProxy::modelClass());
|
||||
}
|
||||
}
|
||||
7
packages/Webkul/Lead/src/Models/TypeProxy.php
Normal file
7
packages/Webkul/Lead/src/Models/TypeProxy.php
Normal file
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Lead\Models;
|
||||
|
||||
use Konekt\Concord\Proxies\ModelProxy;
|
||||
|
||||
class TypeProxy extends ModelProxy {}
|
||||
26
packages/Webkul/Lead/src/Providers/LeadServiceProvider.php
Normal file
26
packages/Webkul/Lead/src/Providers/LeadServiceProvider.php
Normal file
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Lead\Providers;
|
||||
|
||||
use Illuminate\Routing\Router;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
|
||||
class LeadServiceProvider extends ServiceProvider
|
||||
{
|
||||
/**
|
||||
* Bootstrap services.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function boot(Router $router)
|
||||
{
|
||||
$this->loadMigrationsFrom(__DIR__.'/../Database/Migrations');
|
||||
}
|
||||
|
||||
/**
|
||||
* Register services.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register() {}
|
||||
}
|
||||
17
packages/Webkul/Lead/src/Providers/ModuleServiceProvider.php
Normal file
17
packages/Webkul/Lead/src/Providers/ModuleServiceProvider.php
Normal file
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Lead\Providers;
|
||||
|
||||
use Webkul\Core\Providers\BaseModuleServiceProvider;
|
||||
|
||||
class ModuleServiceProvider extends BaseModuleServiceProvider
|
||||
{
|
||||
protected $models = [
|
||||
\Webkul\Lead\Models\Lead::class,
|
||||
\Webkul\Lead\Models\Pipeline::class,
|
||||
\Webkul\Lead\Models\Product::class,
|
||||
\Webkul\Lead\Models\Source::class,
|
||||
\Webkul\Lead\Models\Stage::class,
|
||||
\Webkul\Lead\Models\Type::class,
|
||||
];
|
||||
}
|
||||
254
packages/Webkul/Lead/src/Repositories/LeadRepository.php
Executable file
254
packages/Webkul/Lead/src/Repositories/LeadRepository.php
Executable file
@@ -0,0 +1,254 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Lead\Repositories;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Container\Container;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Str;
|
||||
use Webkul\Attribute\Repositories\AttributeRepository;
|
||||
use Webkul\Attribute\Repositories\AttributeValueRepository;
|
||||
use Webkul\Contact\Repositories\PersonRepository;
|
||||
use Webkul\Core\Eloquent\Repository;
|
||||
use Webkul\Lead\Contracts\Lead;
|
||||
|
||||
class LeadRepository extends Repository
|
||||
{
|
||||
/**
|
||||
* Searchable fields.
|
||||
*/
|
||||
protected $fieldSearchable = [
|
||||
'title',
|
||||
'lead_value',
|
||||
'status',
|
||||
'user_id',
|
||||
'user.name',
|
||||
'person_id',
|
||||
'person.name',
|
||||
'lead_source_id',
|
||||
'lead_type_id',
|
||||
'lead_pipeline_id',
|
||||
'lead_pipeline_stage_id',
|
||||
'created_at',
|
||||
'closed_at',
|
||||
'expected_close_date',
|
||||
];
|
||||
|
||||
/**
|
||||
* Create a new repository instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(
|
||||
protected StageRepository $stageRepository,
|
||||
protected PersonRepository $personRepository,
|
||||
protected ProductRepository $productRepository,
|
||||
protected AttributeRepository $attributeRepository,
|
||||
protected AttributeValueRepository $attributeValueRepository,
|
||||
Container $container
|
||||
) {
|
||||
parent::__construct($container);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify model class name.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function model()
|
||||
{
|
||||
return Lead::class;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get leads query.
|
||||
*
|
||||
* @param int $pipelineId
|
||||
* @param int $pipelineStageId
|
||||
* @param string $term
|
||||
* @param string $createdAtRange
|
||||
* @return mixed
|
||||
*/
|
||||
public function getLeadsQuery($pipelineId, $pipelineStageId, $term, $createdAtRange)
|
||||
{
|
||||
return $this->with([
|
||||
'attribute_values',
|
||||
'pipeline',
|
||||
'stage',
|
||||
])->scopeQuery(function ($query) use ($pipelineId, $pipelineStageId, $term, $createdAtRange) {
|
||||
return $query->select(
|
||||
'leads.id as id',
|
||||
'leads.created_at as created_at',
|
||||
'title',
|
||||
'lead_value',
|
||||
'persons.name as person_name',
|
||||
'leads.person_id as person_id',
|
||||
'lead_pipelines.id as lead_pipeline_id',
|
||||
'lead_pipeline_stages.name as status',
|
||||
'lead_pipeline_stages.id as lead_pipeline_stage_id'
|
||||
)
|
||||
->addSelect(DB::raw('DATEDIFF('.DB::getTablePrefix().'leads.created_at + INTERVAL lead_pipelines.rotten_days DAY, now()) as rotten_days'))
|
||||
->leftJoin('persons', 'leads.person_id', '=', 'persons.id')
|
||||
->leftJoin('lead_pipelines', 'leads.lead_pipeline_id', '=', 'lead_pipelines.id')
|
||||
->leftJoin('lead_pipeline_stages', 'leads.lead_pipeline_stage_id', '=', 'lead_pipeline_stages.id')
|
||||
->where('title', 'like', "%$term%")
|
||||
->where('leads.lead_pipeline_id', $pipelineId)
|
||||
->where('leads.lead_pipeline_stage_id', $pipelineStageId)
|
||||
->when($createdAtRange, function ($query) use ($createdAtRange) {
|
||||
return $query->whereBetween('leads.created_at', $createdAtRange);
|
||||
})
|
||||
->where(function ($query) {
|
||||
if ($userIds = bouncer()->getAuthorizedUserIds()) {
|
||||
$query->whereIn('leads.user_id', $userIds);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Create.
|
||||
*
|
||||
* @return \Webkul\Lead\Contracts\Lead
|
||||
*/
|
||||
public function create(array $data)
|
||||
{
|
||||
/**
|
||||
* If a person is provided, create or update the person and set the `person_id`.
|
||||
*/
|
||||
if (isset($data['person'])) {
|
||||
if (! empty($data['person']['id'])) {
|
||||
$person = $this->personRepository->findOrFail($data['person']['id']);
|
||||
} else {
|
||||
$person = $this->personRepository->create(array_merge($data['person'], [
|
||||
'entity_type' => 'persons',
|
||||
]));
|
||||
}
|
||||
|
||||
$data['person_id'] = $person->id;
|
||||
}
|
||||
|
||||
if (empty($data['expected_close_date'])) {
|
||||
$data['expected_close_date'] = null;
|
||||
}
|
||||
|
||||
$lead = parent::create(array_merge([
|
||||
'lead_pipeline_id' => 1,
|
||||
'lead_pipeline_stage_id' => 1,
|
||||
], $data));
|
||||
|
||||
$this->attributeValueRepository->save(array_merge($data, [
|
||||
'entity_id' => $lead->id,
|
||||
]));
|
||||
|
||||
if (isset($data['products'])) {
|
||||
foreach ($data['products'] as $product) {
|
||||
$this->productRepository->create(array_merge($product, [
|
||||
'lead_id' => $lead->id,
|
||||
'amount' => $product['price'] * $product['quantity'],
|
||||
]));
|
||||
}
|
||||
}
|
||||
|
||||
return $lead;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update.
|
||||
*
|
||||
* @param int $id
|
||||
* @param array|\Illuminate\Database\Eloquent\Collection $attributes
|
||||
* @return \Webkul\Lead\Contracts\Lead
|
||||
*/
|
||||
public function update(array $data, $id, $attributes = [])
|
||||
{
|
||||
/**
|
||||
* If a person is provided, create or update the person and set the `person_id`.
|
||||
* Be cautious, as a lead can be updated without providing person data.
|
||||
* For example, in the lead Kanban section, when switching stages, only the stage will be updated.
|
||||
*/
|
||||
if (isset($data['person'])) {
|
||||
if (! empty($data['person']['id'])) {
|
||||
$person = $this->personRepository->findOrFail($data['person']['id']);
|
||||
} else {
|
||||
$person = $this->personRepository->create(array_merge($data['person'], [
|
||||
'entity_type' => 'persons',
|
||||
]));
|
||||
}
|
||||
|
||||
$data['person_id'] = $person->id;
|
||||
}
|
||||
|
||||
if (isset($data['lead_pipeline_stage_id'])) {
|
||||
$stage = $this->stageRepository->find($data['lead_pipeline_stage_id']);
|
||||
|
||||
if (in_array($stage->code, ['won', 'lost'])) {
|
||||
$data['closed_at'] = $data['closed_at'] ?? Carbon::now();
|
||||
} else {
|
||||
$data['closed_at'] = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($data['expected_close_date'])) {
|
||||
$data['expected_close_date'] = null;
|
||||
}
|
||||
|
||||
$lead = parent::update($data, $id);
|
||||
|
||||
/**
|
||||
* If attributes are provided, only save the provided attributes and return.
|
||||
* A collection of attributes may also be provided, which will be treated as valid,
|
||||
* regardless of whether it is empty or not.
|
||||
*/
|
||||
if (! empty($attributes)) {
|
||||
/**
|
||||
* If attributes are provided as an array, then fetch the attributes from the database;
|
||||
* otherwise, use the provided collection of attributes.
|
||||
*/
|
||||
if (is_array($attributes)) {
|
||||
$conditions = ['entity_type' => $data['entity_type']];
|
||||
|
||||
if (isset($data['quick_add'])) {
|
||||
$conditions['quick_add'] = 1;
|
||||
}
|
||||
|
||||
$attributes = $this->attributeRepository->where($conditions)
|
||||
->whereIn('code', $attributes)
|
||||
->get();
|
||||
}
|
||||
|
||||
$this->attributeValueRepository->save(array_merge($data, [
|
||||
'entity_id' => $lead->id,
|
||||
]), $attributes);
|
||||
|
||||
return $lead;
|
||||
}
|
||||
|
||||
$this->attributeValueRepository->save(array_merge($data, [
|
||||
'entity_id' => $lead->id,
|
||||
]));
|
||||
|
||||
$previousProductIds = $lead->products()->pluck('id');
|
||||
|
||||
if (isset($data['products'])) {
|
||||
foreach ($data['products'] as $productId => $productInputs) {
|
||||
if (Str::contains($productId, 'product_')) {
|
||||
$this->productRepository->create(array_merge([
|
||||
'lead_id' => $lead->id,
|
||||
], $productInputs));
|
||||
} else {
|
||||
if (is_numeric($index = $previousProductIds->search($productId))) {
|
||||
$previousProductIds->forget($index);
|
||||
}
|
||||
|
||||
$this->productRepository->update($productInputs, $productId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($previousProductIds as $productId) {
|
||||
$this->productRepository->delete($productId);
|
||||
}
|
||||
|
||||
return $lead;
|
||||
}
|
||||
}
|
||||
114
packages/Webkul/Lead/src/Repositories/PipelineRepository.php
Executable file
114
packages/Webkul/Lead/src/Repositories/PipelineRepository.php
Executable file
@@ -0,0 +1,114 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Lead\Repositories;
|
||||
|
||||
use Illuminate\Container\Container;
|
||||
use Illuminate\Support\Str;
|
||||
use Webkul\Core\Eloquent\Repository;
|
||||
|
||||
class PipelineRepository extends Repository
|
||||
{
|
||||
/**
|
||||
* Create a new repository instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(
|
||||
protected StageRepository $stageRepository,
|
||||
Container $container
|
||||
) {
|
||||
parent::__construct($container);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify model class name.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function model()
|
||||
{
|
||||
return 'Webkul\Lead\Contracts\Pipeline';
|
||||
}
|
||||
|
||||
/**
|
||||
* Create pipeline.
|
||||
*
|
||||
* @return \Webkul\Lead\Contracts\Pipeline
|
||||
*/
|
||||
public function create(array $data)
|
||||
{
|
||||
if ($data['is_default'] ?? false) {
|
||||
$this->model->query()->update(['is_default' => 0]);
|
||||
}
|
||||
|
||||
$pipeline = $this->model->create($data);
|
||||
|
||||
foreach ($data['stages'] as $stageData) {
|
||||
$this->stageRepository->create(array_merge([
|
||||
'lead_pipeline_id' => $pipeline->id,
|
||||
], $stageData));
|
||||
}
|
||||
|
||||
return $pipeline;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update pipeline.
|
||||
*
|
||||
* @param int $id
|
||||
* @param string $attribute
|
||||
* @return \Webkul\Lead\Contracts\Pipeline
|
||||
*/
|
||||
public function update(array $data, $id, $attribute = 'id')
|
||||
{
|
||||
$pipeline = $this->find($id);
|
||||
|
||||
if ($data['is_default'] ?? false) {
|
||||
$this->model->query()->where('id', '<>', $id)->update(['is_default' => 0]);
|
||||
}
|
||||
|
||||
$pipeline->update($data);
|
||||
|
||||
$previousStageIds = $pipeline->stages()->pluck('id');
|
||||
|
||||
foreach ($data['stages'] as $stageId => $stageData) {
|
||||
if (Str::contains($stageId, 'stage_')) {
|
||||
$this->stageRepository->create(array_merge([
|
||||
'lead_pipeline_id' => $pipeline->id,
|
||||
], $stageData));
|
||||
} else {
|
||||
if (is_numeric($index = $previousStageIds->search($stageId))) {
|
||||
$previousStageIds->forget($index);
|
||||
}
|
||||
|
||||
$this->stageRepository->update($stageData, $stageId);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($previousStageIds as $stageId) {
|
||||
$pipeline->leads()->where('lead_pipeline_stage_id', $stageId)->update([
|
||||
'lead_pipeline_stage_id' => $pipeline->stages()->first()->id,
|
||||
]);
|
||||
|
||||
$this->stageRepository->delete($stageId);
|
||||
}
|
||||
|
||||
return $pipeline;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the default pipeline.
|
||||
*
|
||||
* @return \Webkul\Lead\Contracts\Pipeline
|
||||
*/
|
||||
public function getDefaultPipeline()
|
||||
{
|
||||
$pipeline = $this->findOneByField('is_default', 1);
|
||||
|
||||
if (! $pipeline) {
|
||||
$pipeline = $this->first();
|
||||
}
|
||||
|
||||
return $pipeline;
|
||||
}
|
||||
}
|
||||
18
packages/Webkul/Lead/src/Repositories/ProductRepository.php
Executable file
18
packages/Webkul/Lead/src/Repositories/ProductRepository.php
Executable file
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Lead\Repositories;
|
||||
|
||||
use Webkul\Core\Eloquent\Repository;
|
||||
|
||||
class ProductRepository extends Repository
|
||||
{
|
||||
/**
|
||||
* Specify Model class name
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function model()
|
||||
{
|
||||
return 'Webkul\Lead\Contracts\Product';
|
||||
}
|
||||
}
|
||||
18
packages/Webkul/Lead/src/Repositories/SourceRepository.php
Executable file
18
packages/Webkul/Lead/src/Repositories/SourceRepository.php
Executable file
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Lead\Repositories;
|
||||
|
||||
use Webkul\Core\Eloquent\Repository;
|
||||
|
||||
class SourceRepository extends Repository
|
||||
{
|
||||
/**
|
||||
* Specify Model class name
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function model()
|
||||
{
|
||||
return 'Webkul\Lead\Contracts\Source';
|
||||
}
|
||||
}
|
||||
18
packages/Webkul/Lead/src/Repositories/StageRepository.php
Normal file
18
packages/Webkul/Lead/src/Repositories/StageRepository.php
Normal file
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Lead\Repositories;
|
||||
|
||||
use Webkul\Core\Eloquent\Repository;
|
||||
|
||||
class StageRepository extends Repository
|
||||
{
|
||||
/**
|
||||
* Specify Model class name
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function model()
|
||||
{
|
||||
return 'Webkul\Lead\Contracts\Stage';
|
||||
}
|
||||
}
|
||||
18
packages/Webkul/Lead/src/Repositories/TypeRepository.php
Executable file
18
packages/Webkul/Lead/src/Repositories/TypeRepository.php
Executable file
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Lead\Repositories;
|
||||
|
||||
use Webkul\Core\Eloquent\Repository;
|
||||
|
||||
class TypeRepository extends Repository
|
||||
{
|
||||
/**
|
||||
* Specify Model class name
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function model()
|
||||
{
|
||||
return 'Webkul\Lead\Contracts\Type';
|
||||
}
|
||||
}
|
||||
238
packages/Webkul/Lead/src/Services/MagicAIService.php
Normal file
238
packages/Webkul/Lead/src/Services/MagicAIService.php
Normal file
@@ -0,0 +1,238 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Lead\Services;
|
||||
|
||||
use Exception;
|
||||
use Smalot\PdfParser\Parser;
|
||||
|
||||
class MagicAIService
|
||||
{
|
||||
/**
|
||||
* API endpoint for OpenRouter AI service.
|
||||
*/
|
||||
const OPEN_ROUTER_URL = 'https://openrouter.ai/api/v1/chat/completions';
|
||||
|
||||
/**
|
||||
* Maximum token limit for AI prompt.
|
||||
*/
|
||||
const MAX_TOKENS = 100000;
|
||||
|
||||
/**
|
||||
* Flag to prevent re-entrant calls.
|
||||
*/
|
||||
private static $isExtracting = false;
|
||||
|
||||
/**
|
||||
* Extract data from base64-encoded file.
|
||||
*/
|
||||
public static function extractDataFromFile($base64File)
|
||||
{
|
||||
if (self::$isExtracting) {
|
||||
throw new Exception(trans('admin::app.leads.file.recursive-call'));
|
||||
}
|
||||
|
||||
self::$isExtracting = true;
|
||||
|
||||
try {
|
||||
$text = self::extractTextFromBase64File($base64File);
|
||||
|
||||
if (empty($text)) {
|
||||
throw new Exception(trans('admin::app.leads.file.failed-extract'));
|
||||
}
|
||||
|
||||
return self::processPromptWithAI($text);
|
||||
} catch (Exception $e) {
|
||||
return ['error' => $e->getMessage()];
|
||||
} finally {
|
||||
self::$isExtracting = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract text from base64-encoded file.
|
||||
*/
|
||||
private static function extractTextFromBase64File($base64File)
|
||||
{
|
||||
if (
|
||||
empty($base64File)
|
||||
|| ! base64_decode($base64File, true)
|
||||
) {
|
||||
throw new Exception(trans('admin::app.leads.file.invalid-base64'));
|
||||
}
|
||||
|
||||
$tempFile = tempnam(sys_get_temp_dir(), 'file_');
|
||||
|
||||
file_put_contents($tempFile, self::handleBase64($base64File, 'decode'));
|
||||
|
||||
$mimeType = mime_content_type($tempFile);
|
||||
|
||||
$data = [];
|
||||
|
||||
try {
|
||||
if ($mimeType === 'application/pdf') {
|
||||
$pdfParser = (new Parser)->parseFile($tempFile);
|
||||
|
||||
$data['text'] = $pdfParser->getText();
|
||||
|
||||
$data['images'][] = '';
|
||||
|
||||
$images = $pdfParser->getObjectsByType('XObject', 'Image');
|
||||
|
||||
foreach ($images as $image) {
|
||||
$data['images'][] = self::handleBase64($image->getContent());
|
||||
}
|
||||
} else {
|
||||
$data['text'] = '';
|
||||
|
||||
$data['images'][] = self::handleBase64(self::handleBase64($base64File, 'decode'));
|
||||
}
|
||||
|
||||
if (empty($data)) {
|
||||
throw new Exception(trans('admin::app.leads.file.data-extraction-failed'));
|
||||
}
|
||||
|
||||
return $data;
|
||||
} catch (Exception $e) {
|
||||
throw new Exception($e->getMessage());
|
||||
} finally {
|
||||
@unlink($tempFile);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send extracted data to AI for processing.
|
||||
*/
|
||||
private static function processPromptWithAI($prompt)
|
||||
{
|
||||
$model = core()->getConfigData('general.magic_ai.settings.other_model') ?: core()->getConfigData('general.magic_ai.settings.model');
|
||||
|
||||
$apiKey = core()->getConfigData('general.magic_ai.settings.api_key');
|
||||
|
||||
if (! $apiKey || ! $model) {
|
||||
return ['error' => trans('admin::app.leads.file.missing-api-key')];
|
||||
}
|
||||
|
||||
$promptText = self::truncatePrompt($prompt['text'] ?? '');
|
||||
|
||||
$promptImages = $prompt['images'] ?? [];
|
||||
|
||||
$prompt = array_filter(array_merge([$promptText], $promptImages), function ($value) {
|
||||
return ! empty($value);
|
||||
});
|
||||
|
||||
return self::ask(array_values($prompt), $model, $apiKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Truncate prompt to fit within token limit.
|
||||
*/
|
||||
private static function truncatePrompt($prompt)
|
||||
{
|
||||
if (strlen($prompt) > self::MAX_TOKENS) {
|
||||
$start = mb_substr($prompt, 0, self::MAX_TOKENS * 0.4);
|
||||
|
||||
$end = mb_substr($prompt, -self::MAX_TOKENS * 0.4);
|
||||
|
||||
return $start."\n...\n".$end;
|
||||
}
|
||||
|
||||
return $prompt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send prompt request to AI for processing.
|
||||
*/
|
||||
private static function ask($prompt, $model, $apiKey)
|
||||
{
|
||||
try {
|
||||
$response = \Http::withHeaders([
|
||||
'Content-Type' => 'application/json',
|
||||
'Authorization' => 'Bearer '.$apiKey,
|
||||
])->post(self::OPEN_ROUTER_URL, [
|
||||
'model' => $model,
|
||||
'messages' => [
|
||||
[
|
||||
'role' => 'system',
|
||||
'content' => self::getSystemPrompt(),
|
||||
], [
|
||||
'role' => 'user',
|
||||
'content' => [
|
||||
[
|
||||
'type' => 'text',
|
||||
'text' => $prompt[0],
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
]);
|
||||
|
||||
if ($response->failed()) {
|
||||
throw new Exception($response->body());
|
||||
}
|
||||
|
||||
$data = $response->json();
|
||||
|
||||
if (isset($data['error'])) {
|
||||
throw new Exception($data['error']['message']);
|
||||
}
|
||||
|
||||
return $data;
|
||||
} catch (Exception $e) {
|
||||
return ['error' => trans('admin::app.leads.file.insufficient-info')];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Define system prompt for AI processing.
|
||||
*
|
||||
* @return string System prompt for AI model.
|
||||
*/
|
||||
private static function getSystemPrompt()
|
||||
{
|
||||
return <<<'PROMPT'
|
||||
You are an AI assistant specialized in extracting structured data from text.
|
||||
The user will provide text extracted from a file (in Base64 or plain text).
|
||||
Your task is to accurately extract the following fields. If the value is not available, use the default values provided:
|
||||
|
||||
### **Output Format:**
|
||||
```json
|
||||
{
|
||||
"status": 1,
|
||||
"title": "Untitled Lead",
|
||||
"lead_value": 0,
|
||||
"person": {
|
||||
"name": "Unknown",
|
||||
"emails": {
|
||||
"value": null,
|
||||
"label": null
|
||||
},
|
||||
"contact_numbers": {
|
||||
"value": null,
|
||||
"label": null
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
### **Fields to Extract:**
|
||||
- **Title:** Title of the lead. Default: "Untitled Lead"
|
||||
- **Lead Value:** Value of the lead. Default: 0
|
||||
- **Person Name:** Name of the person. Default: "Unknown"
|
||||
- **Person Email:** Email of the person. Default: null
|
||||
- **Person Email Label:** Label for the email. Default: null
|
||||
- **Person Contact Number:** Contact number of the person. Default: null
|
||||
- **Person Contact Number Label:** Label for the contact number. Default: null
|
||||
PROMPT;
|
||||
}
|
||||
|
||||
/**
|
||||
* process for encoding and decoding base64 data.
|
||||
*/
|
||||
private static function handleBase64($base64, string $type = 'encode')
|
||||
{
|
||||
if ($type === 'encode') {
|
||||
return base64_encode($base64);
|
||||
}
|
||||
|
||||
return base64_decode($base64);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user