File: /var/www/quadcode/app/Console/Commands/AbstractSyncBitrixAndActiveCampaign.php
<?php
namespace App\Console\Commands;
use App\Helpers\ActiveCampaignHelper;
use App\Helpers\BitrixHelper;
use Illuminate\Console\Command;
use Throwable;
abstract class AbstractSyncBitrixAndActiveCampaign extends Command
{
public array $report = [
'contacts_found' => 0,
'unique_contacts_found' => 0,
'subscribed' => 0,
'unsubscribed' => 0,
];
protected ActiveCampaignHelper $activeCampaignHelper;
protected BitrixHelper $bitrixHelper;
protected bool $isVerbose = false;
protected function convertBitrixEntityToActiveCampaignContact(array $entity): ?array
{
$contact = [];
if (!empty($entity['NAME'])) {
$contact['first_name'] = $entity['NAME'];
}
foreach ($entity['EMAIL'] ?? [] as $email) {
$contact['email'] = strtolower($email['VALUE']);
}
if (empty($contact['email'])) {
return null;
}
$contact['phone'] = null;
foreach ($entity['PHONE'] ?? [] as $phone) {
$contact['phone'] = $phone['VALUE'];
}
return $contact;
}
protected function syncContactsToActiveCampaign(string $listId, array $contacts, bool $needUnsubscribe = true): void
{
$contactsFromList = [];
$threshold = 10000;
$limit = 100;
$offset = 0;
$contactsData = $this->activeCampaignHelper->searchContact(['listid' => $listId, 'status' => ActiveCampaignHelper::STATUS_ACTIVE, 'limit' => $limit]);
while (!empty($contactsData['contacts']) || $threshold < 0) {
foreach ($contactsData['contacts'] as $contactFromList) {
$email = strtolower($contactFromList['email']);
$contactFromList['email'] = $email;
$contactsFromList[$email] = $contactFromList;
}
$offset += $limit;
$contactsData = $this->activeCampaignHelper->searchContact(['listid' => $listId, 'status' => ActiveCampaignHelper::STATUS_ACTIVE, 'limit' => $limit, 'offset' => $offset]);
$threshold--;
}
$pb = null;
if (!empty($contacts)) {
$newEmails = [];
foreach ($contacts as $contact) {
$email = $contact['email'];
if (!empty($contactsFromList[$email])) {
unset($contactsFromList[$email]);
continue;
}
$newEmails[] = $email;
}
if (!empty($newEmails)) {
$this->info('Subscribe ' . count($newEmails) . ':');
$this->report['subscribed'] = count($newEmails);
if ($this->isVerbose) {
$pb = $this->output->createProgressBar(count($contacts));
}
foreach ($contacts as $contact) {
if ($this->isVerbose) {
$pb->advance();
}
$email = $contact['email'];
if (!in_array($email, $newEmails)) {
continue;
}
try {
$response = $this->activeCampaignHelper->searchContact(compact('email'));
if (!$response->successful()) {
$this->warn('Response error: ' . $response->status());
continue;
}
$responseData = $response->json();
$externalContact = $responseData['contacts'][0] ?? null;
if (empty($externalContact)) {
$this->line('Create person ' . $contact['email']);
$response = $this->activeCampaignHelper->createContact($contact);
if (!$response->successful()) {
$this->warn('Response error: ' . $response->status());
continue;
}
$responseData = $response->json();
$externalContact = $responseData['contact'] ?? null;
}
if (empty($contact)) {
$this->warn('Contact not found or create');
continue;
}
$this->activeCampaignHelper->subscribeContact($externalContact['id'], $listId);
if (!$response->successful()) {
$this->warn('Response error: ' . $response->status());
continue;
}
} catch (Throwable $exception) {
$this->warn($exception->getMessage());
}
}
if ($this->isVerbose) {
$pb->finish();
}
$this->line('');
}
}
if ($needUnsubscribe && !empty($contactsFromList)) {
$this->info('Unsubscribe ' . count($contactsFromList) . ':');
$this->report['unsubscribed'] = count($contactsFromList);
if ($this->isVerbose) {
$pb = $this->output->createProgressBar(count($contactsFromList));
}
foreach ($contactsFromList as $contactFromList) {
if ($this->isVerbose) {
$pb->advance();
}
$this->activeCampaignHelper->unsubscribeContact($contactFromList['id'], $listId);
}
if ($this->isVerbose) {
$pb->finish();
}
$this->line('');
}
}
protected function syncDealsToActiveCampaign(int $listId, string $stageId, bool $needUnsubscribe = true): void
{
$filter = [
'STAGE_ID' => $stageId,
'>CONTACT_ID' => 0,
];
$select = ['CONTACT_ID', 'UF_*'];
$deals = $this->bitrixHelper->dealList($filter, select: $select);
$this->line('Deals found: ' . count($deals));
$contactsIds = [];
$countriesByContacts = [];
foreach ($deals as $deal) {
if (!empty($deal[BitrixHelper::CUSTOM_DEAL_COUNTRY_BY_IP])) {
$countriesByContacts[$deal['CONTACT_ID']] = $deal[BitrixHelper::CUSTOM_DEAL_COUNTRY_BY_IP];
}
$contactsIds[] = $deal['CONTACT_ID'];
}
$contactsIds = array_unique($contactsIds);
$this->info('Getting contacts');
$bitrixContactsFull = [];
$innerLimit = 50;
for ($innerOffset = 0; $innerOffset < count($contactsIds); $innerOffset += $innerLimit) {
$batchContactsIds = array_slice($contactsIds, $innerOffset, $innerLimit);
$filter = ['ID' => $batchContactsIds];
$select = ['NAME', 'EMAIL', 'PHONE'];
$bitrixContactsFull = array_merge($bitrixContactsFull, $this->bitrixHelper->contactsList($filter, $select));
}
$this->line('Contacts found: ' . count($bitrixContactsFull));
$contacts = [];
$bitrixContacts = $bitrixContactsFull;
$pb = null;
if ($this->isVerbose) {
$pb = $this->output->createProgressBar(count($bitrixContacts));
}
foreach ($bitrixContacts as $bitrixContact) {
if ($this->isVerbose) {
$pb->advance();
}
$contact = $this->convertBitrixEntityToActiveCampaignContact($bitrixContact);
if (empty($contact)) {
continue;
}
if (!empty($countriesByContacts[$bitrixContact['ID']])) {
$contact['lang_by_browser'] = $countriesByContacts[$bitrixContact['ID']];
}
$contacts[$contact['email']] = $contact;
}
if ($this->isVerbose) {
$pb->finish();
}
$this->line('');
$uniqueEmails = array_unique(array_column($contacts, 'email'));
$this->line('Contacts found: ' . count($contactsIds));
$this->line('Unique contacts found: ' . count($uniqueEmails));
$this->report['contacts_found'] = count($contactsIds);
$this->report['unique_contacts_found'] = count($uniqueEmails);
$this->syncContactsToActiveCampaign($listId, $contacts, $needUnsubscribe);
$this->info('Done');
}
protected function syncLeadsToActiveCampaign(int $listId, string $statusId, bool $needUnsubscribe = true): void
{
$filter = [
'STATUS_ID' => $statusId,
'>LAST_ACTIVITY_TIME' => date('Y-m-d', strtotime('-2 week')),
];
$select = ['NAME', 'EMAIL', 'PHONE'];
$leads = $this->bitrixHelper->leadList($filter, select: $select);
$contacts = [];
foreach ($leads as $lead) {
$contact = $this->convertBitrixEntityToActiveCampaignContact($lead);
if (empty($contact)) {
continue;
}
$contacts[$contact['email']] = $contact;
}
$uniqueEmails = array_unique(array_column($contacts, 'email'));
$this->line('Contacts found: ' . count($contacts));
$this->line('Unique contacts found: ' . count($uniqueEmails));
$this->report['contacts_found'] = count($contacts);
$this->report['unique_contacts_found'] = count($uniqueEmails);
$this->syncContactsToActiveCampaign($listId, $contacts, $needUnsubscribe);
}
}