add: full multi-tenancy control
This commit is contained in:
74
packages/Webkul/Automation/src/Config/workflows.php
Normal file
74
packages/Webkul/Automation/src/Config/workflows.php
Normal file
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'trigger_entities' => [
|
||||
|
||||
'leads' => [
|
||||
'name' => 'Leads',
|
||||
'class' => 'Webkul\Automation\Helpers\Entity\Lead',
|
||||
'events' => [
|
||||
[
|
||||
'event' => 'lead.create.after',
|
||||
'name' => 'Created',
|
||||
], [
|
||||
'event' => 'lead.update.after',
|
||||
'name' => 'Updated',
|
||||
], [
|
||||
'event' => 'lead.delete.before',
|
||||
'name' => 'Deleted',
|
||||
],
|
||||
],
|
||||
],
|
||||
|
||||
'activities' => [
|
||||
'name' => 'Activities',
|
||||
'class' => 'Webkul\Automation\Helpers\Entity\Activity',
|
||||
'events' => [
|
||||
[
|
||||
'event' => 'activity.create.after',
|
||||
'name' => 'Created',
|
||||
], [
|
||||
'event' => 'activity.update.after',
|
||||
'name' => 'Updated',
|
||||
], [
|
||||
'event' => 'activity.delete.before',
|
||||
'name' => 'Deleted',
|
||||
],
|
||||
],
|
||||
],
|
||||
|
||||
'persons' => [
|
||||
'name' => 'Persons',
|
||||
'class' => 'Webkul\Automation\Helpers\Entity\Person',
|
||||
'events' => [
|
||||
[
|
||||
'event' => 'contacts.person.create.after',
|
||||
'name' => 'Created',
|
||||
], [
|
||||
'event' => 'contacts.person.update.after',
|
||||
'name' => 'Updated',
|
||||
], [
|
||||
'event' => 'contacts.person.delete.before',
|
||||
'name' => 'Deleted',
|
||||
],
|
||||
],
|
||||
],
|
||||
|
||||
'quotes' => [
|
||||
'name' => 'Quotes',
|
||||
'class' => 'Webkul\Automation\Helpers\Entity\Quote',
|
||||
'events' => [
|
||||
[
|
||||
'event' => 'quote.create.after',
|
||||
'name' => 'Created',
|
||||
], [
|
||||
'event' => 'quote.update.after',
|
||||
'name' => 'Updated',
|
||||
], [
|
||||
'event' => 'quote.delete.before',
|
||||
'name' => 'Deleted',
|
||||
],
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
5
packages/Webkul/Automation/src/Contracts/Webhook.php
Normal file
5
packages/Webkul/Automation/src/Contracts/Webhook.php
Normal file
@@ -0,0 +1,5 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Automation\Contracts;
|
||||
|
||||
interface Webhook {}
|
||||
5
packages/Webkul/Automation/src/Contracts/Workflow.php
Normal file
5
packages/Webkul/Automation/src/Contracts/Workflow.php
Normal file
@@ -0,0 +1,5 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Automation\Contracts;
|
||||
|
||||
interface Workflow {}
|
||||
@@ -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('workflows', function (Blueprint $table) {
|
||||
$table->increments('id');
|
||||
$table->string('name');
|
||||
$table->string('description')->nullable();
|
||||
$table->string('entity_type');
|
||||
$table->string('event');
|
||||
$table->string('condition_type')->default('and');
|
||||
$table->json('conditions')->nullable();
|
||||
$table->json('actions')->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('workflows');
|
||||
}
|
||||
};
|
||||
@@ -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.
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
Schema::create('webhooks', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('name');
|
||||
$table->string('entity_type');
|
||||
$table->string('description')->nullable();
|
||||
$table->string('method');
|
||||
$table->string('end_point');
|
||||
$table->json('query_params')->nullable();
|
||||
$table->json('headers')->nullable();
|
||||
$table->string('payload_type');
|
||||
$table->string('raw_payload_type');
|
||||
$table->json('payload')->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('webhooks');
|
||||
}
|
||||
};
|
||||
103
packages/Webkul/Automation/src/Helpers/Entity.php
Normal file
103
packages/Webkul/Automation/src/Helpers/Entity.php
Normal file
@@ -0,0 +1,103 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Automation\Helpers;
|
||||
|
||||
use Webkul\Attribute\Repositories\AttributeRepository;
|
||||
use Webkul\EmailTemplate\Repositories\EmailTemplateRepository;
|
||||
|
||||
class Entity
|
||||
{
|
||||
/**
|
||||
* Create a new repository instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(
|
||||
protected AttributeRepository $attributeRepository,
|
||||
protected EmailTemplateRepository $emailTemplateRepository
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Returns events to match for the entity
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getEvents()
|
||||
{
|
||||
$entities = config('workflows.trigger_entities');
|
||||
|
||||
$events = [];
|
||||
|
||||
foreach ($entities as $key => $entity) {
|
||||
$object = app($entity['class']);
|
||||
|
||||
$events[$key] = [
|
||||
'id' => $key,
|
||||
'name' => $entity['name'],
|
||||
'events' => $entity['events'],
|
||||
];
|
||||
}
|
||||
|
||||
return $events;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns conditions to match for the entity
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getConditions()
|
||||
{
|
||||
$entities = config('workflows.trigger_entities');
|
||||
|
||||
$conditions = [];
|
||||
|
||||
foreach ($entities as $key => $entity) {
|
||||
$object = app($entity['class']);
|
||||
|
||||
$conditions[$key] = $object->getConditions();
|
||||
}
|
||||
|
||||
return $conditions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns workflow actions
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getActions()
|
||||
{
|
||||
$entities = config('workflows.trigger_entities');
|
||||
|
||||
$conditions = [];
|
||||
|
||||
foreach ($entities as $key => $entity) {
|
||||
$object = app($entity['class']);
|
||||
|
||||
$conditions[$key] = $object->getActions();
|
||||
}
|
||||
|
||||
return $conditions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns placeholders for email templates
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getEmailTemplatePlaceholders()
|
||||
{
|
||||
$entities = config('workflows.trigger_entities');
|
||||
|
||||
$placeholders = [];
|
||||
|
||||
foreach ($entities as $key => $entity) {
|
||||
$object = app($entity['class']);
|
||||
|
||||
$placeholders[] = $object->getEmailTemplatePlaceholders($entity);
|
||||
}
|
||||
|
||||
return $placeholders;
|
||||
}
|
||||
}
|
||||
232
packages/Webkul/Automation/src/Helpers/Entity/AbstractEntity.php
Normal file
232
packages/Webkul/Automation/src/Helpers/Entity/AbstractEntity.php
Normal file
@@ -0,0 +1,232 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Automation\Helpers\Entity;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Webkul\Attribute\Repositories\AttributeRepository;
|
||||
use Webkul\Automation\Repositories\WebhookRepository;
|
||||
use Webkul\Automation\Services\WebhookService;
|
||||
|
||||
abstract class AbstractEntity
|
||||
{
|
||||
/**
|
||||
* Attribute repository instance.
|
||||
*/
|
||||
protected AttributeRepository $attributeRepository;
|
||||
|
||||
/**
|
||||
* Create a new repository instance.
|
||||
*/
|
||||
public function __construct(
|
||||
protected WebhookService $webhookService,
|
||||
protected WebhookRepository $webhookRepository,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Listing of the entities.
|
||||
*/
|
||||
abstract public function getEntity(mixed $entity);
|
||||
|
||||
/**
|
||||
* Returns workflow actions.
|
||||
*/
|
||||
abstract public function getActions();
|
||||
|
||||
/**
|
||||
* Execute workflow actions.
|
||||
*/
|
||||
abstract public function executeActions(mixed $workflow, mixed $entity): void;
|
||||
|
||||
/**
|
||||
* Returns attributes for workflow conditions.
|
||||
*/
|
||||
public function getConditions(): array
|
||||
{
|
||||
return $this->getAttributes($this->entityType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get attributes for entity.
|
||||
*/
|
||||
public function getAttributes(string $entityType, array $skipAttributes = ['textarea', 'image', 'file', 'address']): array
|
||||
{
|
||||
$attributes = [];
|
||||
|
||||
foreach ($this->attributeRepository->findByField('entity_type', $entityType) as $attribute) {
|
||||
if (in_array($attribute->type, $skipAttributes)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($attribute->lookup_type) {
|
||||
$options = [];
|
||||
} else {
|
||||
$options = $attribute->options;
|
||||
}
|
||||
|
||||
$attributes[] = [
|
||||
'id' => $attribute->code,
|
||||
'type' => $attribute->type,
|
||||
'name' => $attribute->name,
|
||||
'lookup_type' => $attribute->lookup_type,
|
||||
'options' => $options,
|
||||
];
|
||||
}
|
||||
|
||||
return $attributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns placeholders for email templates.
|
||||
*/
|
||||
public function getEmailTemplatePlaceholders(array $entity): array
|
||||
{
|
||||
$menuItems = [];
|
||||
|
||||
foreach ($this->getAttributes($this->entityType) as $attribute) {
|
||||
$menuItems[] = [
|
||||
'text' => $attribute['name'],
|
||||
'value' => '{%'.$this->entityType.'.'.$attribute['id'].'%}',
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
'text' => $entity['name'],
|
||||
'menu' => $menuItems,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace placeholders with values.
|
||||
*/
|
||||
public function replacePlaceholders(mixed $entity, string $content): string
|
||||
{
|
||||
foreach ($this->getAttributes($this->entityType, []) as $attribute) {
|
||||
$value = '';
|
||||
|
||||
switch ($attribute['type']) {
|
||||
case 'price':
|
||||
$value = core()->formatBasePrice($entity->{$attribute['id']});
|
||||
|
||||
break;
|
||||
|
||||
case 'boolean':
|
||||
$value = $entity->{$attribute['id']} ? __('admin::app.common.yes') : __('admin::app.common.no');
|
||||
|
||||
break;
|
||||
|
||||
case 'select':
|
||||
case 'radio':
|
||||
case 'lookup':
|
||||
if ($attribute['lookup_type']) {
|
||||
$option = $this->attributeRepository->getLookUpEntity($attribute['lookup_type'], $entity->{$attribute['id']});
|
||||
} else {
|
||||
$option = $attribute['options']->where('id', $entity->{$attribute['id']})->first();
|
||||
}
|
||||
|
||||
$value = $option ? $option->name : '';
|
||||
|
||||
break;
|
||||
|
||||
case 'multiselect':
|
||||
case 'checkbox':
|
||||
if ($attribute['lookup_type']) {
|
||||
$options = $this->attributeRepository->getLookUpEntity($attribute['lookup_type'], explode(',', $entity->{$attribute['id']}));
|
||||
} else {
|
||||
$options = $attribute['options']->whereIn('id', explode(',', $entity->{$attribute['id']}));
|
||||
}
|
||||
|
||||
$optionsLabels = [];
|
||||
|
||||
foreach ($options as $key => $option) {
|
||||
$optionsLabels[] = $option->name;
|
||||
}
|
||||
|
||||
$value = implode(', ', $optionsLabels);
|
||||
|
||||
break;
|
||||
|
||||
case 'email':
|
||||
case 'phone':
|
||||
if (! is_array($entity->{$attribute['id']})) {
|
||||
break;
|
||||
}
|
||||
|
||||
$optionsLabels = [];
|
||||
|
||||
foreach ($entity->{$attribute['id']} as $item) {
|
||||
$optionsLabels[] = $item['value'].' ('.$item['label'].')';
|
||||
}
|
||||
|
||||
$value = implode(', ', $optionsLabels);
|
||||
|
||||
break;
|
||||
|
||||
case 'address':
|
||||
if (! $entity->{$attribute['id']} || ! count(array_filter($entity->{$attribute['id']}))) {
|
||||
break;
|
||||
}
|
||||
|
||||
$value = $entity->{$attribute['id']}['address'].'<br>'
|
||||
.$entity->{$attribute['id']}['postcode'].' '.$entity->{$attribute['id']}['city'].'<br>'
|
||||
.core()->state_name($entity->{$attribute['id']}['state']).'<br>'
|
||||
.core()->country_name($entity->{$attribute['id']}['country']).'<br>';
|
||||
|
||||
break;
|
||||
|
||||
case 'date':
|
||||
if ($entity->{$attribute['id']}) {
|
||||
$value = ! is_object($entity->{$attribute['id']})
|
||||
? Carbon::parse($entity->{$attribute['id']})
|
||||
: $entity->{$attribute['id']}->format('D M d, Y');
|
||||
} else {
|
||||
$value = 'N/A';
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'datetime':
|
||||
if ($entity->{$attribute['id']}) {
|
||||
$value = ! is_object($entity->{$attribute['id']})
|
||||
? Carbon::parse($entity->{$attribute['id']})
|
||||
: $entity->{$attribute['id']}->format('D M d, Y H:i A');
|
||||
} else {
|
||||
$value = 'N/A';
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
$value = $entity->{$attribute['id']};
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
$content = strtr($content, [
|
||||
'{%'.$this->entityType.'.'.$attribute['id'].'%}' => $value,
|
||||
'{% '.$this->entityType.'.'.$attribute['id'].' %}' => $value,
|
||||
]);
|
||||
}
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Trigger webhook.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function triggerWebhook(int $webhookId, mixed $entity)
|
||||
{
|
||||
$webhook = $this->webhookRepository->findOrFail($webhookId);
|
||||
|
||||
$payload = [
|
||||
'method' => $webhook->method,
|
||||
'query_params' => $this->replacePlaceholders($entity, json_encode($webhook->query_params)),
|
||||
'end_point' => $this->replacePlaceholders($entity, $webhook->end_point),
|
||||
'payload' => $this->replacePlaceholders($entity, json_encode($webhook->payload)),
|
||||
'headers' => $this->replacePlaceholders($entity, json_encode($webhook->headers)),
|
||||
];
|
||||
|
||||
$this->webhookService->triggerWebhook($payload);
|
||||
}
|
||||
}
|
||||
323
packages/Webkul/Automation/src/Helpers/Entity/Activity.php
Normal file
323
packages/Webkul/Automation/src/Helpers/Entity/Activity.php
Normal file
@@ -0,0 +1,323 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Automation\Helpers\Entity;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use Webkul\Activity\Contracts\Activity as ContractsActivity;
|
||||
use Webkul\Activity\Repositories\ActivityRepository;
|
||||
use Webkul\Admin\Notifications\Common;
|
||||
use Webkul\Attribute\Repositories\AttributeRepository;
|
||||
use Webkul\Automation\Repositories\WebhookRepository;
|
||||
use Webkul\Automation\Services\WebhookService;
|
||||
use Webkul\Contact\Repositories\PersonRepository;
|
||||
use Webkul\EmailTemplate\Repositories\EmailTemplateRepository;
|
||||
use Webkul\Lead\Repositories\LeadRepository;
|
||||
|
||||
class Activity extends AbstractEntity
|
||||
{
|
||||
/**
|
||||
* Define the entity type.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $entityType = 'activities';
|
||||
|
||||
/**
|
||||
* Create a new repository instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(
|
||||
protected AttributeRepository $attributeRepository,
|
||||
protected EmailTemplateRepository $emailTemplateRepository,
|
||||
protected LeadRepository $leadRepository,
|
||||
protected PersonRepository $personRepository,
|
||||
protected ActivityRepository $activityRepository,
|
||||
protected WebhookRepository $webhookRepository,
|
||||
protected WebhookService $webhookService
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Get the attributes for workflow conditions.
|
||||
*/
|
||||
public function getAttributes(string $entityType, array $skipAttributes = []): array
|
||||
{
|
||||
$attributes = [
|
||||
[
|
||||
'id' => 'title',
|
||||
'type' => 'text',
|
||||
'name' => 'Title',
|
||||
'lookup_type' => null,
|
||||
'options' => collect(),
|
||||
], [
|
||||
'id' => 'type',
|
||||
'type' => 'multiselect',
|
||||
'name' => 'Type',
|
||||
'lookup_type' => null,
|
||||
'options' => collect([
|
||||
(object) [
|
||||
'id' => 'note',
|
||||
'name' => 'Note',
|
||||
], (object) [
|
||||
'id' => 'call',
|
||||
'name' => 'Call',
|
||||
], (object) [
|
||||
'id' => 'meeting',
|
||||
'name' => 'Meeting',
|
||||
], (object) [
|
||||
'id' => 'lunch',
|
||||
'name' => 'Lunch',
|
||||
], (object) [
|
||||
'id' => 'file',
|
||||
'name' => 'File',
|
||||
],
|
||||
]),
|
||||
], [
|
||||
'id' => 'location',
|
||||
'type' => 'text',
|
||||
'name' => 'Location',
|
||||
'lookup_type' => null,
|
||||
'options' => collect(),
|
||||
], [
|
||||
'id' => 'comment',
|
||||
'type' => 'textarea',
|
||||
'name' => 'Comment',
|
||||
'lookup_type' => null,
|
||||
'options' => collect(),
|
||||
], [
|
||||
'id' => 'schedule_from',
|
||||
'type' => 'datetime',
|
||||
'name' => 'Schedule From',
|
||||
'lookup_type' => null,
|
||||
'options' => collect(),
|
||||
], [
|
||||
'id' => 'schedule_to',
|
||||
'type' => 'datetime',
|
||||
'name' => 'Schedule To',
|
||||
'lookup_type' => null,
|
||||
'options' => collect(),
|
||||
], [
|
||||
'id' => 'user_id',
|
||||
'type' => 'select',
|
||||
'name' => 'User',
|
||||
'lookup_type' => 'users',
|
||||
'options' => $this->attributeRepository->getLookUpOptions('users'),
|
||||
],
|
||||
];
|
||||
|
||||
return $attributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns placeholders for email templates.
|
||||
*/
|
||||
public function getEmailTemplatePlaceholders(array $entity): array
|
||||
{
|
||||
$emailTemplates = parent::getEmailTemplatePlaceholders($entity);
|
||||
|
||||
$emailTemplates['menu'][] = [
|
||||
'text' => 'Participants',
|
||||
'value' => '{%activities.participants%}',
|
||||
];
|
||||
|
||||
return $emailTemplates;
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace placeholders with values.
|
||||
*/
|
||||
public function replacePlaceholders(mixed $entity, string $content): string
|
||||
{
|
||||
$content = parent::replacePlaceholders($entity, $content);
|
||||
|
||||
$value = '<ul style="padding-left: 18px;margin: 0;">';
|
||||
|
||||
foreach ($entity->participants as $participant) {
|
||||
$value .= '<li>'.($participant->user ? $participant->user->name : $participant->person->name).'</li>';
|
||||
}
|
||||
|
||||
$value .= '</ul>';
|
||||
|
||||
return strtr($content, [
|
||||
'{%'.$this->entityType.'.participants%}' => $value,
|
||||
'{% '.$this->entityType.'.participants %}' => $value,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Listing of the entities.
|
||||
*/
|
||||
public function getEntity(mixed $entity): mixed
|
||||
{
|
||||
if (! $entity instanceof ContractsActivity) {
|
||||
$entity = $this->activityRepository->find($entity);
|
||||
}
|
||||
|
||||
return $entity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns workflow actions.
|
||||
*/
|
||||
public function getActions(): array
|
||||
{
|
||||
$emailTemplates = $this->emailTemplateRepository->all(['id', 'name']);
|
||||
|
||||
$webhooksOptions = $this->webhookRepository->all(['id', 'name']);
|
||||
|
||||
return [
|
||||
[
|
||||
'id' => 'update_related_leads',
|
||||
'name' => trans('admin::app.settings.workflows.helpers.update-related-leads'),
|
||||
'attributes' => $this->getAttributes('leads'),
|
||||
], [
|
||||
'id' => 'send_email_to_sales_owner',
|
||||
'name' => trans('admin::app.settings.workflows.helpers.send-email-to-sales-owner'),
|
||||
'options' => $emailTemplates,
|
||||
], [
|
||||
'id' => 'send_email_to_participants',
|
||||
'name' => trans('admin::app.settings.workflows.helpers.send-email-to-participants'),
|
||||
'options' => $emailTemplates,
|
||||
], [
|
||||
'id' => 'trigger_webhook',
|
||||
'name' => trans('admin::app.settings.workflows.helpers.add-webhook'),
|
||||
'options' => $webhooksOptions,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute workflow actions.
|
||||
*/
|
||||
public function executeActions(mixed $workflow, mixed $activity): void
|
||||
{
|
||||
foreach ($workflow->actions as $action) {
|
||||
switch ($action['id']) {
|
||||
case 'update_related_leads':
|
||||
$leadIds = $this->activityRepository->getModel()
|
||||
->leftJoin('lead_activities', 'activities.id', 'lead_activities.activity_id')
|
||||
->leftJoin('leads', 'lead_activities.lead_id', 'leads.id')
|
||||
->addSelect('leads.id')
|
||||
->where('activities.id', $activity->id)
|
||||
->pluck('id');
|
||||
|
||||
foreach ($leadIds as $leadId) {
|
||||
$this->leadRepository->update(
|
||||
[
|
||||
'entity_type' => 'leads',
|
||||
$action['attribute'] => $action['value'],
|
||||
],
|
||||
$leadId,
|
||||
[$action['attribute']]
|
||||
);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'send_email_to_sales_owner':
|
||||
$emailTemplate = $this->emailTemplateRepository->find($action['value']);
|
||||
|
||||
if (! $emailTemplate) {
|
||||
break;
|
||||
}
|
||||
|
||||
try {
|
||||
Mail::queue(new Common([
|
||||
'to' => $activity->user->email,
|
||||
'subject' => $this->replacePlaceholders($activity, $emailTemplate->subject),
|
||||
'body' => $this->replacePlaceholders($activity, $emailTemplate->content),
|
||||
'attachments' => [
|
||||
[
|
||||
'name' => 'invite.ics',
|
||||
'mime' => 'text/calendar',
|
||||
'content' => $this->getICSContent($activity),
|
||||
],
|
||||
],
|
||||
]));
|
||||
} catch (\Exception $e) {
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'send_email_to_participants':
|
||||
$emailTemplate = $this->emailTemplateRepository->find($action['value']);
|
||||
|
||||
if (! $emailTemplate) {
|
||||
break;
|
||||
}
|
||||
|
||||
try {
|
||||
foreach ($activity->participants as $participant) {
|
||||
Mail::queue(new Common([
|
||||
'to' => $participant->user
|
||||
? $participant->user->email
|
||||
: data_get($participant->person->emails, '*.value'),
|
||||
'subject' => $this->replacePlaceholders($activity, $emailTemplate->subject),
|
||||
'body' => $this->replacePlaceholders($activity, $emailTemplate->content),
|
||||
'attachments' => [
|
||||
[
|
||||
'name' => 'invite.ics',
|
||||
'mime' => 'text/calendar',
|
||||
'content' => $this->getICSContent($activity),
|
||||
],
|
||||
],
|
||||
]));
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'trigger_webhook':
|
||||
try {
|
||||
$this->triggerWebhook($action['value'], $activity);
|
||||
} catch (\Exception $e) {
|
||||
report($e);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns .ics file for attachments.
|
||||
*/
|
||||
public function getICSContent(ContractsActivity $activity): string
|
||||
{
|
||||
$content = [
|
||||
'BEGIN:VCALENDAR',
|
||||
'VERSION:2.0',
|
||||
'PRODID:-//Krayincrm//Krayincrm//EN',
|
||||
'BEGIN:VEVENT',
|
||||
'UID:'.time().'-'.$activity->id,
|
||||
'DTSTAMP:'.Carbon::now()->format('YmdTHis'),
|
||||
'CREATED:'.$activity->created_at->format('YmdTHis'),
|
||||
'SEQUENCE:1',
|
||||
'ORGANIZER;CN='.$activity->user->name.':MAILTO:'.$activity->user->email,
|
||||
];
|
||||
|
||||
foreach ($activity->participants as $participant) {
|
||||
if ($participant->user) {
|
||||
$content[] = 'ATTENDEE;ROLE=REQ-PARTICIPANT;CN='.$participant->user->name.';PARTSTAT=NEEDS-ACTION:MAILTO:'.$participant->user->email;
|
||||
} else {
|
||||
foreach (data_get($participant->person->emails, '*.value') as $email) {
|
||||
$content[] = 'ATTENDEE;ROLE=REQ-PARTICIPANT;CN='.$participant->person->name.';PARTSTAT=NEEDS-ACTION:MAILTO:'.$email;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$content = array_merge($content, [
|
||||
'DTSTART:'.$activity->schedule_from->format('YmdTHis'),
|
||||
'DTEND:'.$activity->schedule_to->format('YmdTHis'),
|
||||
'SUMMARY:'.$activity->title,
|
||||
'LOCATION:'.$activity->location,
|
||||
'DESCRIPTION:'.$activity->comment,
|
||||
'END:VEVENT',
|
||||
'END:VCALENDAR',
|
||||
]);
|
||||
|
||||
return implode("\r\n", $content);
|
||||
}
|
||||
}
|
||||
210
packages/Webkul/Automation/src/Helpers/Entity/Lead.php
Normal file
210
packages/Webkul/Automation/src/Helpers/Entity/Lead.php
Normal file
@@ -0,0 +1,210 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Automation\Helpers\Entity;
|
||||
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use Webkul\Activity\Repositories\ActivityRepository;
|
||||
use Webkul\Admin\Notifications\Common;
|
||||
use Webkul\Attribute\Repositories\AttributeRepository;
|
||||
use Webkul\Automation\Repositories\WebhookRepository;
|
||||
use Webkul\Automation\Services\WebhookService;
|
||||
use Webkul\Contact\Repositories\PersonRepository;
|
||||
use Webkul\EmailTemplate\Repositories\EmailTemplateRepository;
|
||||
use Webkul\Lead\Contracts\Lead as ContractsLead;
|
||||
use Webkul\Lead\Repositories\LeadRepository;
|
||||
use Webkul\Tag\Repositories\TagRepository;
|
||||
|
||||
class Lead extends AbstractEntity
|
||||
{
|
||||
/**
|
||||
* Define the entity type.
|
||||
*/
|
||||
protected string $entityType = 'leads';
|
||||
|
||||
/**
|
||||
* Create a new repository instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(
|
||||
protected AttributeRepository $attributeRepository,
|
||||
protected EmailTemplateRepository $emailTemplateRepository,
|
||||
protected LeadRepository $leadRepository,
|
||||
protected ActivityRepository $activityRepository,
|
||||
protected PersonRepository $personRepository,
|
||||
protected TagRepository $tagRepository,
|
||||
protected WebhookRepository $webhookRepository,
|
||||
protected WebhookService $webhookService
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Listing of the entities.
|
||||
*/
|
||||
public function getEntity(mixed $entity)
|
||||
{
|
||||
if (! $entity instanceof ContractsLead) {
|
||||
$entity = $this->leadRepository->find($entity);
|
||||
}
|
||||
|
||||
return $entity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns attributes.
|
||||
*/
|
||||
public function getAttributes(string $entityType, array $skipAttributes = ['textarea', 'image', 'file', 'address']): array
|
||||
{
|
||||
return parent::getAttributes($entityType, $skipAttributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns workflow actions.
|
||||
*/
|
||||
public function getActions(): array
|
||||
{
|
||||
$emailTemplates = $this->emailTemplateRepository->all(['id', 'name']);
|
||||
|
||||
$webhooksOptions = $this->webhookRepository->all(['id', 'name']);
|
||||
|
||||
return [
|
||||
[
|
||||
'id' => 'update_lead',
|
||||
'name' => trans('admin::app.settings.workflows.helpers.update-lead'),
|
||||
'attributes' => $this->getAttributes('leads'),
|
||||
], [
|
||||
'id' => 'update_person',
|
||||
'name' => trans('admin::app.settings.workflows.helpers.update-person'),
|
||||
'attributes' => $this->getAttributes('persons'),
|
||||
], [
|
||||
'id' => 'send_email_to_person',
|
||||
'name' => trans('admin::app.settings.workflows.helpers.send-email-to-person'),
|
||||
'options' => $emailTemplates,
|
||||
], [
|
||||
'id' => 'send_email_to_sales_owner',
|
||||
'name' => trans('admin::app.settings.workflows.helpers.send-email-to-sales-owner'),
|
||||
'options' => $emailTemplates,
|
||||
], [
|
||||
'id' => 'add_tag',
|
||||
'name' => trans('admin::app.settings.workflows.helpers.add-tag'),
|
||||
], [
|
||||
'id' => 'add_note_as_activity',
|
||||
'name' => trans('admin::app.settings.workflows.helpers.add-note-as-activity'),
|
||||
], [
|
||||
'id' => 'trigger_webhook',
|
||||
'name' => trans('admin::app.settings.workflows.helpers.add-webhook'),
|
||||
'options' => $webhooksOptions,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute workflow actions.
|
||||
*/
|
||||
public function executeActions(mixed $workflow, mixed $lead): void
|
||||
{
|
||||
foreach ($workflow->actions as $action) {
|
||||
switch ($action['id']) {
|
||||
case 'update_lead':
|
||||
$this->leadRepository->update(
|
||||
[
|
||||
'entity_type' => 'leads',
|
||||
$action['attribute'] => $action['value'],
|
||||
],
|
||||
$lead->id,
|
||||
[$action['attribute']]
|
||||
);
|
||||
|
||||
break;
|
||||
|
||||
case 'update_person':
|
||||
$this->personRepository->update([
|
||||
'entity_type' => 'persons',
|
||||
$action['attribute'] => $action['value'],
|
||||
], $lead->person_id);
|
||||
|
||||
break;
|
||||
|
||||
case 'send_email_to_person':
|
||||
$emailTemplate = $this->emailTemplateRepository->find($action['value']);
|
||||
|
||||
if (! $emailTemplate) {
|
||||
break;
|
||||
}
|
||||
|
||||
try {
|
||||
Mail::queue(new Common([
|
||||
'to' => data_get($lead->person->emails, '*.value'),
|
||||
'subject' => $this->replacePlaceholders($lead, $emailTemplate->subject),
|
||||
'body' => $this->replacePlaceholders($lead, $emailTemplate->content),
|
||||
]));
|
||||
} catch (\Exception $e) {
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'send_email_to_sales_owner':
|
||||
$emailTemplate = $this->emailTemplateRepository->find($action['value']);
|
||||
|
||||
if (! $emailTemplate) {
|
||||
break;
|
||||
}
|
||||
|
||||
try {
|
||||
Mail::queue(new Common([
|
||||
'to' => $lead->user->email,
|
||||
'subject' => $this->replacePlaceholders($lead, $emailTemplate->subject),
|
||||
'body' => $this->replacePlaceholders($lead, $emailTemplate->content),
|
||||
]));
|
||||
} catch (\Exception $e) {
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'add_tag':
|
||||
$colors = [
|
||||
'#337CFF',
|
||||
'#FEBF00',
|
||||
'#E5549F',
|
||||
'#27B6BB',
|
||||
'#FB8A3F',
|
||||
'#43AF52',
|
||||
];
|
||||
|
||||
if (! $tag = $this->tagRepository->findOneByField('name', $action['value'])) {
|
||||
$tag = $this->tagRepository->create([
|
||||
'name' => $action['value'],
|
||||
'color' => $colors[rand(0, 5)],
|
||||
'user_id' => auth()->guard('user')->user()->id,
|
||||
]);
|
||||
}
|
||||
|
||||
if (! $lead->tags->contains($tag->id)) {
|
||||
$lead->tags()->attach($tag->id);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'add_note_as_activity':
|
||||
$activity = $this->activityRepository->create([
|
||||
'type' => 'note',
|
||||
'comment' => $action['value'],
|
||||
'is_done' => 1,
|
||||
'user_id' => auth()->guard('user')->user()->id,
|
||||
]);
|
||||
|
||||
$lead->activities()->attach($activity->id);
|
||||
|
||||
break;
|
||||
|
||||
case 'trigger_webhook':
|
||||
try {
|
||||
$this->triggerWebhook($action['value'], $lead);
|
||||
} catch (\Exception $e) {
|
||||
report($e);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
140
packages/Webkul/Automation/src/Helpers/Entity/Person.php
Normal file
140
packages/Webkul/Automation/src/Helpers/Entity/Person.php
Normal file
@@ -0,0 +1,140 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Automation\Helpers\Entity;
|
||||
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use Webkul\Admin\Notifications\Common;
|
||||
use Webkul\Attribute\Repositories\AttributeRepository;
|
||||
use Webkul\Automation\Contracts\Workflow;
|
||||
use Webkul\Automation\Repositories\WebhookRepository;
|
||||
use Webkul\Automation\Services\WebhookService;
|
||||
use Webkul\Contact\Contracts\Person as PersonContract;
|
||||
use Webkul\Contact\Repositories\PersonRepository;
|
||||
use Webkul\EmailTemplate\Repositories\EmailTemplateRepository;
|
||||
use Webkul\Lead\Repositories\LeadRepository;
|
||||
|
||||
class Person extends AbstractEntity
|
||||
{
|
||||
/**
|
||||
* Define the entity type.
|
||||
*/
|
||||
protected string $entityType = 'persons';
|
||||
|
||||
/**
|
||||
* Create a new repository instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(
|
||||
protected AttributeRepository $attributeRepository,
|
||||
protected EmailTemplateRepository $emailTemplateRepository,
|
||||
protected LeadRepository $leadRepository,
|
||||
protected PersonRepository $personRepository,
|
||||
protected WebhookRepository $webhookRepository,
|
||||
protected WebhookService $webhookService
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Listing of the entities.
|
||||
*/
|
||||
public function getEntity(mixed $entity): mixed
|
||||
{
|
||||
if (! $entity instanceof PersonContract) {
|
||||
$entity = $this->personRepository->find($entity);
|
||||
}
|
||||
|
||||
return $entity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns workflow actions.
|
||||
*/
|
||||
public function getActions(): array
|
||||
{
|
||||
$emailTemplates = $this->emailTemplateRepository->all(['id', 'name']);
|
||||
|
||||
$webhooksOptions = $this->webhookRepository->all(['id', 'name']);
|
||||
|
||||
return [
|
||||
[
|
||||
'id' => 'update_person',
|
||||
'name' => trans('admin::app.settings.workflows.helpers.update-person'),
|
||||
'attributes' => $this->getAttributes('persons'),
|
||||
], [
|
||||
'id' => 'update_related_leads',
|
||||
'name' => trans('admin::app.settings.workflows.helpers.update-related-leads'),
|
||||
'attributes' => $this->getAttributes('leads'),
|
||||
], [
|
||||
'id' => 'send_email_to_person',
|
||||
'name' => trans('admin::app.settings.workflows.helpers.send-email-to-person'),
|
||||
'options' => $emailTemplates,
|
||||
], [
|
||||
'id' => 'trigger_webhook',
|
||||
'name' => trans('admin::app.settings.workflows.helpers.add-webhook'),
|
||||
'options' => $webhooksOptions,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute workflow actions.
|
||||
*/
|
||||
public function executeActions(mixed $workflow, mixed $person): void
|
||||
{
|
||||
foreach ($workflow->actions as $action) {
|
||||
switch ($action['id']) {
|
||||
case 'update_person':
|
||||
$this->personRepository->update([
|
||||
'entity_type' => 'persons',
|
||||
$action['attribute'] => $action['value'],
|
||||
], $person->id);
|
||||
|
||||
break;
|
||||
|
||||
case 'update_related_leads':
|
||||
$leads = $this->leadRepository->findByField('person_id', $person->id);
|
||||
|
||||
foreach ($leads as $lead) {
|
||||
$this->leadRepository->update(
|
||||
[
|
||||
'entity_type' => 'leads',
|
||||
$action['attribute'] => $action['value'],
|
||||
],
|
||||
$lead->id,
|
||||
[$action['attribute']]
|
||||
);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'send_email_to_person':
|
||||
$emailTemplate = $this->emailTemplateRepository->find($action['value']);
|
||||
|
||||
if (! $emailTemplate) {
|
||||
break;
|
||||
}
|
||||
|
||||
try {
|
||||
Mail::queue(new Common([
|
||||
'to' => data_get($person->emails, '*.value'),
|
||||
'subject' => $this->replacePlaceholders($person, $emailTemplate->subject),
|
||||
'body' => $this->replacePlaceholders($person, $emailTemplate->content),
|
||||
]));
|
||||
} catch (\Exception $e) {
|
||||
report($e);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'trigger_webhook':
|
||||
try {
|
||||
$this->triggerWebhook($action['value'], $person);
|
||||
} catch (\Exception $e) {
|
||||
report($e);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
172
packages/Webkul/Automation/src/Helpers/Entity/Quote.php
Normal file
172
packages/Webkul/Automation/src/Helpers/Entity/Quote.php
Normal file
@@ -0,0 +1,172 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Automation\Helpers\Entity;
|
||||
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use Webkul\Admin\Notifications\Common;
|
||||
use Webkul\Attribute\Repositories\AttributeRepository;
|
||||
use Webkul\Automation\Repositories\WebhookRepository;
|
||||
use Webkul\Automation\Services\WebhookService;
|
||||
use Webkul\Contact\Repositories\PersonRepository;
|
||||
use Webkul\EmailTemplate\Repositories\EmailTemplateRepository;
|
||||
use Webkul\Lead\Repositories\LeadRepository;
|
||||
use Webkul\Quote\Contracts\Quote as ContractsQuote;
|
||||
use Webkul\Quote\Repositories\QuoteRepository;
|
||||
|
||||
class Quote extends AbstractEntity
|
||||
{
|
||||
/**
|
||||
* Define the entity type.
|
||||
*/
|
||||
protected string $entityType = 'quotes';
|
||||
|
||||
/**
|
||||
* Create a new repository instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(
|
||||
protected AttributeRepository $attributeRepository,
|
||||
protected EmailTemplateRepository $emailTemplateRepository,
|
||||
protected QuoteRepository $quoteRepository,
|
||||
protected LeadRepository $leadRepository,
|
||||
protected PersonRepository $personRepository,
|
||||
protected WebhookRepository $webhookRepository,
|
||||
protected WebhookService $webhookService
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Listing of the entities.
|
||||
*/
|
||||
public function getEntity(mixed $entity): mixed
|
||||
{
|
||||
if (! $entity instanceof ContractsQuote) {
|
||||
$entity = $this->quoteRepository->find($entity);
|
||||
}
|
||||
|
||||
return $entity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns workflow actions.
|
||||
*/
|
||||
public function getActions(): array
|
||||
{
|
||||
$emailTemplates = $this->emailTemplateRepository->all(['id', 'name']);
|
||||
|
||||
$webhookOptions = $this->webhookRepository->all(['id', 'name']);
|
||||
|
||||
return [
|
||||
[
|
||||
'id' => 'update_quote',
|
||||
'name' => trans('admin::app.settings.workflows.helpers.update-quote'),
|
||||
'attributes' => $this->getAttributes('quotes'),
|
||||
], [
|
||||
'id' => 'update_person',
|
||||
'name' => trans('admin::app.settings.workflows.helpers.update-person'),
|
||||
'attributes' => $this->getAttributes('persons'),
|
||||
], [
|
||||
'id' => 'update_related_leads',
|
||||
'name' => trans('admin::app.settings.workflows.helpers.update-related-leads'),
|
||||
'attributes' => $this->getAttributes('leads'),
|
||||
], [
|
||||
'id' => 'send_email_to_person',
|
||||
'name' => trans('admin::app.settings.workflows.helpers.send-email-to-person'),
|
||||
'options' => $emailTemplates,
|
||||
], [
|
||||
'id' => 'send_email_to_sales_owner',
|
||||
'name' => trans('admin::app.settings.workflows.helpers.send-email-to-sales-owner'),
|
||||
'options' => $emailTemplates,
|
||||
], [
|
||||
'id' => 'trigger_webhook',
|
||||
'name' => trans('admin::app.settings.workflows.helpers.add-webhook'),
|
||||
'options' => $webhookOptions,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute workflow actions.
|
||||
*/
|
||||
public function executeActions(mixed $workflow, mixed $quote): void
|
||||
{
|
||||
foreach ($workflow->actions as $action) {
|
||||
switch ($action['id']) {
|
||||
case 'update_quote':
|
||||
$this->quoteRepository->update([
|
||||
'entity_type' => 'quotes',
|
||||
$action['attribute'] => $action['value'],
|
||||
], $quote->id);
|
||||
|
||||
break;
|
||||
|
||||
case 'update_person':
|
||||
$this->personRepository->update([
|
||||
'entity_type' => 'persons',
|
||||
$action['attribute'] => $action['value'],
|
||||
], $quote->person_id);
|
||||
|
||||
break;
|
||||
|
||||
case 'update_related_leads':
|
||||
foreach ($quote->leads as $lead) {
|
||||
$this->leadRepository->update(
|
||||
[
|
||||
'entity_type' => 'leads',
|
||||
$action['attribute'] => $action['value'],
|
||||
],
|
||||
$lead->id,
|
||||
[$action['attribute']]
|
||||
);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'send_email_to_person':
|
||||
$emailTemplate = $this->emailTemplateRepository->find($action['value']);
|
||||
|
||||
if (! $emailTemplate) {
|
||||
break;
|
||||
}
|
||||
|
||||
try {
|
||||
Mail::queue(new Common([
|
||||
'to' => data_get($quote->person->emails, '*.value'),
|
||||
'subject' => $this->replacePlaceholders($quote, $emailTemplate->subject),
|
||||
'body' => $this->replacePlaceholders($quote, $emailTemplate->content),
|
||||
]));
|
||||
} catch (\Exception $e) {
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'send_email_to_sales_owner':
|
||||
$emailTemplate = $this->emailTemplateRepository->find($action['value']);
|
||||
|
||||
if (! $emailTemplate) {
|
||||
break;
|
||||
}
|
||||
|
||||
try {
|
||||
Mail::queue(new Common([
|
||||
'to' => $quote->user->email,
|
||||
'subject' => $this->replacePlaceholders($quote, $emailTemplate->subject),
|
||||
'body' => $this->replacePlaceholders($quote, $emailTemplate->content),
|
||||
]));
|
||||
} catch (\Exception $e) {
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'trigger_webhook':
|
||||
try {
|
||||
$this->triggerWebhook($action['value'], $quote);
|
||||
} catch (\Exception $e) {
|
||||
report($e);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
183
packages/Webkul/Automation/src/Helpers/Validator.php
Normal file
183
packages/Webkul/Automation/src/Helpers/Validator.php
Normal file
@@ -0,0 +1,183 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Automation\Helpers;
|
||||
|
||||
class Validator
|
||||
{
|
||||
/**
|
||||
* Validate workflow for condition
|
||||
*
|
||||
* @param \Webkul\Automation\Contracts\Workflow $workflow
|
||||
* @param mixed $entity
|
||||
* @return bool
|
||||
*/
|
||||
public function validate($workflow, $entity)
|
||||
{
|
||||
if (! $workflow->conditions) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$validConditionCount = $totalConditionCount = 0;
|
||||
|
||||
foreach ($workflow->conditions as $condition) {
|
||||
if (! $condition['attribute']
|
||||
|| ! isset($condition['value'])
|
||||
|| is_null($condition['value'])
|
||||
|| $condition['value'] == ''
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$totalConditionCount++;
|
||||
|
||||
if ($workflow->condition_type == 'and') {
|
||||
if (! $this->validateEntity($condition, $entity)) {
|
||||
return false;
|
||||
} else {
|
||||
$validConditionCount++;
|
||||
}
|
||||
} else {
|
||||
if ($this->validateEntity($condition, $entity)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $validConditionCount == $totalConditionCount ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate object
|
||||
*
|
||||
* @param array $condition
|
||||
* @param mixed $entity
|
||||
* @return bool
|
||||
*/
|
||||
private function validateEntity($condition, $entity)
|
||||
{
|
||||
return $this->validateAttribute(
|
||||
$condition,
|
||||
$this->getAttributeValue($condition, $entity)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return value for the attribute
|
||||
*
|
||||
* @param array $condition
|
||||
* @param mixed $entity
|
||||
* @return bool
|
||||
*/
|
||||
public function getAttributeValue($condition, $entity)
|
||||
{
|
||||
$value = $entity->{$condition['attribute']};
|
||||
|
||||
if (! in_array($condition['attribute_type'], ['multiselect', 'checkbox'])) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
return $value ? explode(',', $value) : [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate attribute value for condition
|
||||
*
|
||||
* @param array $condition
|
||||
* @param mixed $attributeValue
|
||||
* @return bool
|
||||
*/
|
||||
public function validateAttribute($condition, $attributeValue)
|
||||
{
|
||||
switch ($condition['operator']) {
|
||||
case '==': case '!=':
|
||||
if (is_array($condition['value'])) {
|
||||
if (! is_array($attributeValue)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$result = ! empty(array_intersect($condition['value'], $attributeValue));
|
||||
} elseif (is_object($attributeValue)) {
|
||||
$result = $attributeValue->value == $condition['value'];
|
||||
} else {
|
||||
if (is_array($attributeValue)) {
|
||||
$result = count($attributeValue) == 1 && array_shift($attributeValue) == $condition['value'];
|
||||
} else {
|
||||
$result = $attributeValue == $condition['value'];
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case '<=': case '>':
|
||||
if (! is_scalar($attributeValue)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$result = $attributeValue <= $condition['value'];
|
||||
|
||||
break;
|
||||
|
||||
case '>=': case '<':
|
||||
if (! is_scalar($attributeValue)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$result = $attributeValue >= $condition['value'];
|
||||
|
||||
break;
|
||||
|
||||
case '{}': case '!{}':
|
||||
if (is_scalar($attributeValue) && is_array($condition['value'])) {
|
||||
foreach ($condition['value'] as $item) {
|
||||
if (stripos($attributeValue, $item) !== false) {
|
||||
$result = true;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
} elseif (is_array($condition['value'])) {
|
||||
if (! is_array($attributeValue)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$result = ! empty(array_intersect($condition['value'], $attributeValue));
|
||||
} else {
|
||||
if (is_array($attributeValue)) {
|
||||
$result = self::validateArrayValues($attributeValue, $condition['value']);
|
||||
} else {
|
||||
$result = strpos($attributeValue, $condition['value']) !== false;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (in_array($condition['operator'], ['!=', '>', '<', '!{}'])) {
|
||||
$result = ! $result;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the condition value against a multi dimensional array recursively
|
||||
*/
|
||||
private static function validateArrayValues(array $attributeValue, string $conditionValue): bool
|
||||
{
|
||||
if (in_array($conditionValue, $attributeValue, true) === true) {
|
||||
return true;
|
||||
}
|
||||
|
||||
foreach ($attributeValue as $subValue) {
|
||||
if (! is_array($subValue)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (self::validateArrayValues($subValue, $conditionValue) === true) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
45
packages/Webkul/Automation/src/Listeners/Entity.php
Normal file
45
packages/Webkul/Automation/src/Listeners/Entity.php
Normal file
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Automation\Listeners;
|
||||
|
||||
use Webkul\Automation\Helpers\Validator;
|
||||
use Webkul\Automation\Repositories\WorkflowRepository;
|
||||
|
||||
class Entity
|
||||
{
|
||||
/**
|
||||
* Create a new repository instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(
|
||||
protected WorkflowRepository $workflowRepository,
|
||||
protected Validator $validator
|
||||
) {}
|
||||
|
||||
/**
|
||||
* @param string $eventName
|
||||
* @param mixed $entity
|
||||
* @return void
|
||||
*/
|
||||
public function process($eventName, $entity)
|
||||
{
|
||||
$workflows = $this->workflowRepository->findByField('event', $eventName);
|
||||
|
||||
foreach ($workflows as $workflow) {
|
||||
$workflowEntity = app(config('workflows.trigger_entities.'.$workflow->entity_type.'.class'));
|
||||
|
||||
$entity = $workflowEntity->getEntity($entity);
|
||||
|
||||
if (! $this->validator->validate($workflow, $entity)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
$workflowEntity->executeActions($workflow, $entity);
|
||||
} catch (\Exception $e) {
|
||||
logger()->error($e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
41
packages/Webkul/Automation/src/Models/Webhook.php
Normal file
41
packages/Webkul/Automation/src/Models/Webhook.php
Normal file
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Automation\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Webkul\Automation\Contracts\Webhook as ContractsWebhook;
|
||||
|
||||
class Webhook extends Model implements ContractsWebhook
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array<int, string>
|
||||
*/
|
||||
protected $fillable = [
|
||||
'name',
|
||||
'entity_type',
|
||||
'description',
|
||||
'method',
|
||||
'end_point',
|
||||
'query_params',
|
||||
'headers',
|
||||
'payload_type',
|
||||
'raw_payload_type',
|
||||
'payload',
|
||||
];
|
||||
|
||||
/**
|
||||
* The attributes that should be cast to native types.
|
||||
*
|
||||
* @var array<string, string>
|
||||
*/
|
||||
protected $casts = [
|
||||
'query_params' => 'array',
|
||||
'headers' => 'array',
|
||||
'payload' => 'array',
|
||||
];
|
||||
}
|
||||
7
packages/Webkul/Automation/src/Models/WebhookProxy.php
Normal file
7
packages/Webkul/Automation/src/Models/WebhookProxy.php
Normal file
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Automation\Models;
|
||||
|
||||
use Konekt\Concord\Proxies\ModelProxy;
|
||||
|
||||
class WebhookProxy extends ModelProxy {}
|
||||
24
packages/Webkul/Automation/src/Models/Workflow.php
Normal file
24
packages/Webkul/Automation/src/Models/Workflow.php
Normal file
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Automation\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Webkul\Automation\Contracts\Workflow as WorkflowContract;
|
||||
|
||||
class Workflow extends Model implements WorkflowContract
|
||||
{
|
||||
protected $casts = [
|
||||
'conditions' => 'array',
|
||||
'actions' => 'array',
|
||||
];
|
||||
|
||||
protected $fillable = [
|
||||
'name',
|
||||
'description',
|
||||
'entity_type',
|
||||
'event',
|
||||
'condition_type',
|
||||
'conditions',
|
||||
'actions',
|
||||
];
|
||||
}
|
||||
7
packages/Webkul/Automation/src/Models/WorkflowProxy.php
Normal file
7
packages/Webkul/Automation/src/Models/WorkflowProxy.php
Normal file
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Automation\Models;
|
||||
|
||||
use Konekt\Concord\Proxies\ModelProxy;
|
||||
|
||||
class WorkflowProxy extends ModelProxy {}
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Automation\Providers;
|
||||
|
||||
use Webkul\Automation\Models\Webhook;
|
||||
use Webkul\Automation\Models\Workflow;
|
||||
use Webkul\Core\Providers\BaseModuleServiceProvider;
|
||||
|
||||
class ModuleServiceProvider extends BaseModuleServiceProvider
|
||||
{
|
||||
/**
|
||||
* Define the modals to map with this module.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $models = [
|
||||
Workflow::class,
|
||||
Webhook::class,
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Automation\Providers;
|
||||
|
||||
use Illuminate\Support\Facades\Event;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
|
||||
class WorkflowServiceProvider extends ServiceProvider
|
||||
{
|
||||
/**
|
||||
* Bootstrap services.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function boot()
|
||||
{
|
||||
$this->loadMigrationsFrom(__DIR__.'/../Database/Migrations');
|
||||
|
||||
Event::listen('*', function ($eventName, array $data) {
|
||||
if (! in_array($eventName, data_get(config('workflows.trigger_entities'), '*.events.*.event'))) {
|
||||
return;
|
||||
}
|
||||
|
||||
app(\Webkul\Automation\Listeners\Entity::class)->process($eventName, current($data));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Register services.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register()
|
||||
{
|
||||
$this->registerConfig();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register package config.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function registerConfig()
|
||||
{
|
||||
$this->mergeConfigFrom(dirname(__DIR__).'/Config/workflows.php', 'workflows');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Automation\Repositories;
|
||||
|
||||
use Webkul\Automation\Contracts\Webhook;
|
||||
use Webkul\Core\Eloquent\Repository;
|
||||
|
||||
class WebhookRepository extends Repository
|
||||
{
|
||||
/**
|
||||
* Specify Model class name.
|
||||
*/
|
||||
public function model(): string
|
||||
{
|
||||
return Webhook::class;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Automation\Repositories;
|
||||
|
||||
use Webkul\Automation\Contracts\Workflow;
|
||||
use Webkul\Core\Eloquent\Repository;
|
||||
|
||||
class WorkflowRepository extends Repository
|
||||
{
|
||||
/**
|
||||
* Specify Model class name.
|
||||
*/
|
||||
public function model(): string
|
||||
{
|
||||
return Workflow::class;
|
||||
}
|
||||
}
|
||||
438
packages/Webkul/Automation/src/Services/WebhookService.php
Normal file
438
packages/Webkul/Automation/src/Services/WebhookService.php
Normal file
@@ -0,0 +1,438 @@
|
||||
<?php
|
||||
|
||||
namespace Webkul\Automation\Services;
|
||||
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\Exception\RequestException;
|
||||
use GuzzleHttp\Psr7\Message;
|
||||
use Webkul\Contact\Repositories\PersonRepository;
|
||||
|
||||
class WebhookService
|
||||
{
|
||||
/**
|
||||
* The GuzzleHttp client instance.
|
||||
*/
|
||||
protected Client $client;
|
||||
|
||||
/**
|
||||
* Create a new webhook service instance.
|
||||
*/
|
||||
public function __construct(protected PersonRepository $personRepository)
|
||||
{
|
||||
$this->client = new Client([
|
||||
'timeout' => 30,
|
||||
'connect_timeout' => 10,
|
||||
'verify' => true,
|
||||
'http_errors' => false,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Trigger the webhook.
|
||||
*/
|
||||
public function triggerWebhook(mixed $data): array
|
||||
{
|
||||
if (
|
||||
! isset($data['method'])
|
||||
|| ! isset($data['end_point'])
|
||||
) {
|
||||
return [
|
||||
'status' => 'error',
|
||||
'response' => 'Missing required fields: method or end_point',
|
||||
];
|
||||
}
|
||||
|
||||
$headers = isset($data['headers']) ? $this->parseJsonField($data['headers']) : [];
|
||||
$payload = isset($data['payload']) ? $data['payload'] : null;
|
||||
$data['end_point'] = $this->appendQueryParams($data['end_point'], $data['query_params'] ?? '');
|
||||
|
||||
$formattedHeaders = $this->formatHeaders($headers);
|
||||
|
||||
$options = $this->buildRequestOptions($data['method'], $formattedHeaders, $payload);
|
||||
|
||||
try {
|
||||
$response = $this->client->request(
|
||||
strtoupper($data['method']),
|
||||
$data['end_point'],
|
||||
$options,
|
||||
);
|
||||
|
||||
return [
|
||||
'status' => 'success',
|
||||
'response' => $response->getBody()->getContents(),
|
||||
'status_code' => $response->getStatusCode(),
|
||||
'headers' => $response->getHeaders(),
|
||||
];
|
||||
} catch (RequestException $e) {
|
||||
return [
|
||||
'status' => 'error',
|
||||
'response' => $e->hasResponse() ? Message::toString($e->getResponse()) : $e->getMessage(),
|
||||
'status_code' => $e->hasResponse() ? $e->getResponse()->getStatusCode() : null,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse JSON field safely.
|
||||
*/
|
||||
protected function parseJsonField(mixed $field): array
|
||||
{
|
||||
if (is_array($field)) {
|
||||
return $field;
|
||||
}
|
||||
|
||||
if (is_string($field)) {
|
||||
$decoded = json_decode($field, true);
|
||||
|
||||
if (
|
||||
json_last_error() === JSON_ERROR_NONE
|
||||
&& is_array($decoded)
|
||||
) {
|
||||
return $decoded;
|
||||
}
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Build request options based on method and content type.
|
||||
*/
|
||||
protected function buildRequestOptions(string $method, array $headers, mixed $payload): array
|
||||
{
|
||||
$options = [];
|
||||
|
||||
if (! empty($headers)) {
|
||||
$options['headers'] = $headers;
|
||||
}
|
||||
|
||||
if (
|
||||
$payload !== null
|
||||
&& ! in_array(strtoupper($method), ['GET', 'HEAD'])
|
||||
) {
|
||||
$contentType = $this->getContentType($headers);
|
||||
|
||||
switch ($contentType) {
|
||||
case 'application/json':
|
||||
$options['json'] = $this->prepareJsonPayload($payload);
|
||||
|
||||
break;
|
||||
|
||||
case 'application/x-www-form-urlencoded':
|
||||
$options['form_params'] = $this->prepareFormPayload($payload);
|
||||
|
||||
break;
|
||||
|
||||
case 'multipart/form-data':
|
||||
$options['multipart'] = $this->prepareMultipartPayload($payload);
|
||||
|
||||
break;
|
||||
|
||||
case 'text/plain':
|
||||
case 'text/xml':
|
||||
case 'application/xml':
|
||||
$options['body'] = $this->prepareRawPayload($payload);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
$options = array_merge($options, $this->autoDetectPayloadFormat($payload));
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare JSON payload.
|
||||
*/
|
||||
protected function prepareJsonPayload(mixed $payload): mixed
|
||||
{
|
||||
if (is_string($payload)) {
|
||||
$decoded = json_decode($payload, true);
|
||||
|
||||
if (json_last_error() === JSON_ERROR_NONE) {
|
||||
return $decoded;
|
||||
}
|
||||
|
||||
return $payload;
|
||||
}
|
||||
|
||||
if (is_array($payload)) {
|
||||
return $this->formatPayload($payload);
|
||||
}
|
||||
|
||||
return $payload;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare form payload.
|
||||
*/
|
||||
protected function prepareFormPayload(mixed $payload): array
|
||||
{
|
||||
if (is_string($payload)) {
|
||||
$decoded = json_decode($payload, true);
|
||||
|
||||
if (
|
||||
json_last_error() === JSON_ERROR_NONE
|
||||
&& is_array($decoded)
|
||||
) {
|
||||
return $this->formatPayload($decoded);
|
||||
}
|
||||
|
||||
parse_str($payload, $parsed);
|
||||
|
||||
return $parsed ?: [];
|
||||
}
|
||||
|
||||
if (is_array($payload)) {
|
||||
return $this->formatPayload($payload);
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare multipart payload.
|
||||
*/
|
||||
protected function prepareMultipartPayload(mixed $payload): array
|
||||
{
|
||||
$formattedPayload = $this->prepareFormPayload($payload);
|
||||
|
||||
return $this->buildMultipartData($formattedPayload);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare raw payload.
|
||||
*/
|
||||
protected function prepareRawPayload(mixed $payload): string
|
||||
{
|
||||
if (is_string($payload)) {
|
||||
return $payload;
|
||||
}
|
||||
|
||||
if (is_array($payload)) {
|
||||
return json_encode($payload);
|
||||
}
|
||||
|
||||
return (string) $payload;
|
||||
}
|
||||
|
||||
/**
|
||||
* Auto-detect payload format when no content-type is specified.
|
||||
*/
|
||||
protected function autoDetectPayloadFormat(mixed $payload): array
|
||||
{
|
||||
if (is_string($payload)) {
|
||||
$decoded = json_decode($payload, true);
|
||||
|
||||
if (json_last_error() === JSON_ERROR_NONE) {
|
||||
return ['json' => $decoded];
|
||||
}
|
||||
|
||||
if (
|
||||
strpos($payload, '=') !== false
|
||||
&& strpos($payload, '&') !== false
|
||||
) {
|
||||
parse_str($payload, $parsed);
|
||||
|
||||
return ['form_params' => $parsed];
|
||||
}
|
||||
|
||||
return ['body' => $payload];
|
||||
}
|
||||
|
||||
if (is_array($payload)) {
|
||||
$formatted = $this->formatPayload($payload);
|
||||
|
||||
return ['json' => $formatted];
|
||||
}
|
||||
|
||||
return ['body' => (string) $payload];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get content type from headers.
|
||||
*/
|
||||
protected function getContentType(array $headers): string
|
||||
{
|
||||
foreach ($headers as $key => $value) {
|
||||
if (strtolower($key) === 'content-type') {
|
||||
$contentType = strtolower(trim(explode(';', $value)[0]));
|
||||
|
||||
return $contentType;
|
||||
}
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Build multipart data array.
|
||||
*/
|
||||
protected function buildMultipartData(array $payload): array
|
||||
{
|
||||
$multipart = [];
|
||||
|
||||
foreach ($payload as $key => $value) {
|
||||
$multipart[] = [
|
||||
'name' => $key,
|
||||
'contents' => is_array($value) ? json_encode($value) : (string) $value,
|
||||
];
|
||||
}
|
||||
|
||||
return $multipart;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format headers array.
|
||||
*/
|
||||
protected function formatHeaders(array $headers): array
|
||||
{
|
||||
if (empty($headers)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$formattedHeaders = [];
|
||||
|
||||
if ($this->isKeyValuePairArray($headers)) {
|
||||
foreach ($headers as $header) {
|
||||
if (
|
||||
isset($header['key'])
|
||||
&& array_key_exists('value', $header)
|
||||
) {
|
||||
if (
|
||||
isset($header['disabled'])
|
||||
&& $header['disabled']
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (
|
||||
isset($header['enabled'])
|
||||
&& ! $header['enabled']
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$formattedHeaders[$header['key']] = $header['value'];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$formattedHeaders = $headers;
|
||||
}
|
||||
|
||||
return $formattedHeaders;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format any incoming payload into a clean associative array.
|
||||
*/
|
||||
protected function formatPayload(mixed $payload): array
|
||||
{
|
||||
if (empty($payload)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (
|
||||
is_array($payload)
|
||||
&& isset($payload['key'])
|
||||
&& array_key_exists('value', $payload)
|
||||
) {
|
||||
return [$payload['key'] => $payload['value']];
|
||||
}
|
||||
|
||||
if (
|
||||
is_array($payload)
|
||||
&& array_is_list($payload)
|
||||
&& $this->isKeyValuePairArray($payload)
|
||||
) {
|
||||
$formatted = [];
|
||||
|
||||
foreach ($payload as $item) {
|
||||
if (
|
||||
isset($item['key'])
|
||||
&& array_key_exists('value', $item)
|
||||
) {
|
||||
if (
|
||||
isset($item['disabled'])
|
||||
&& $item['disabled']
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (
|
||||
isset($item['enabled'])
|
||||
&& ! $item['enabled']
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$formatted[$item['key']] = $item['value'];
|
||||
}
|
||||
}
|
||||
|
||||
return $formatted;
|
||||
}
|
||||
|
||||
return is_array($payload) ? $payload : [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if array is a key-value pair array.
|
||||
*/
|
||||
protected function isKeyValuePairArray(array $array): bool
|
||||
{
|
||||
if (empty($array)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (
|
||||
isset($array['key'])
|
||||
&& array_key_exists('value', $array)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (array_is_list($array)) {
|
||||
return collect($array)->every(fn ($item) => is_array($item) && isset($item['key']) && array_key_exists('value', $item)
|
||||
);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Append query parameters to the endpoint URL.
|
||||
*/
|
||||
protected function appendQueryParams(string $endPoint, string $queryParamsJson): string
|
||||
{
|
||||
$queryParams = json_decode($queryParamsJson, true);
|
||||
|
||||
if (
|
||||
json_last_error() !== JSON_ERROR_NONE
|
||||
|| ! is_array($queryParams)
|
||||
) {
|
||||
return $endPoint;
|
||||
}
|
||||
|
||||
$queryArray = [];
|
||||
|
||||
foreach ($queryParams as $param) {
|
||||
if (
|
||||
isset($param['key'])
|
||||
&& array_key_exists('value', $param)
|
||||
) {
|
||||
$queryArray[$param['key']] = $param['value'];
|
||||
}
|
||||
}
|
||||
|
||||
$queryString = http_build_query($queryArray);
|
||||
|
||||
$glue = str_contains($endPoint, '?') ? '&' : '?';
|
||||
|
||||
return $endPoint.($queryString ? $glue.$queryString : '');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user