Initial xentral_oss_20.3.c9ffacf
This commit is contained in:
@@ -0,0 +1,308 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\Hubspot;
|
||||
|
||||
use ApplicationCore;
|
||||
use Xentral\Components\Database\Database;
|
||||
use Xentral\Core\DependencyInjection\ContainerInterface;
|
||||
use Xentral\Modules\Country\Gateway\StateGateway;
|
||||
use Xentral\Modules\Hubspot\RequestQueues\HubspotRequestQueuesGateway;
|
||||
use Xentral\Modules\Hubspot\RequestQueues\HubspotRequestQueuesService;
|
||||
use Xentral\Modules\Hubspot\Scheduler\HubspotProcessSchedulerTask;
|
||||
use Xentral\Modules\Hubspot\Scheduler\HubspotPullContactsTask;
|
||||
use Xentral\Modules\Hubspot\Scheduler\HubspotPullDealsTask;
|
||||
use Xentral\Modules\Hubspot\Scheduler\HubspotPullEngagementsTask;
|
||||
use Xentral\Modules\Hubspot\Validators\ContactValidator;
|
||||
use Xentral\Modules\Hubspot\Validators\DealValidator;
|
||||
use Xentral\Modules\SubscriptionCycle\Scheduler\TaskMutexService;
|
||||
|
||||
final class Bootstrap
|
||||
{
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public static function registerServices()
|
||||
{
|
||||
return [
|
||||
'HubspotContactService' => 'onInitHubspotContactService',
|
||||
'HubspotDealService' => 'onInitHubspotDealService',
|
||||
'HubspotClientService' => 'onInitHubspotClientService',
|
||||
'HubspotHttpClientService' => 'onInitHubspotHttpClientService',
|
||||
'HubspotConfigurationService' => 'onInitHubspotConfigurationService',
|
||||
'HubspotPullContactsTask' => 'onInitHubspotPullContactsTask',
|
||||
'HubspotContactGateway' => 'onInitHubspotContactGateway',
|
||||
'HubspotDealGateway' => 'onInitHubspotDealGateway',
|
||||
'HubspotContactPropertyService' => 'onInitHubspotContactPropertyService',
|
||||
'HubspotContactPropertyGateway' => 'onInitHubspotContactPropertyGateway',
|
||||
'HubspotPullDealsTask' => 'onInitHubspotPullDealsTask',
|
||||
'HubspotDealPropertyService' => 'onInitHubspotDealPropertyService',
|
||||
'HubspotProcessSchedulerTask' => 'onInitHubspotProcessSchedulerTask',
|
||||
'HubspotRequestQueuesGateway' => 'onInitRequestQueuesGateway',
|
||||
'HubspotRequestQueuesService' => 'onInitRequestQueuesService',
|
||||
'HubspotEventService' => 'onInitHubspotEventService',
|
||||
HubspotEngagementService::class => 'onInitHubspotEngagementService',
|
||||
HubspotPullEngagementsTask::class => 'onInitHubspotPullEngagementsTask',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ContainerInterface $container
|
||||
*
|
||||
* @return HubspotContactService
|
||||
*/
|
||||
public static function onInitHubspotContactService(ContainerInterface $container)
|
||||
{
|
||||
/** @var ApplicationCore $app */
|
||||
$app = $container->get('LegacyApplication');
|
||||
|
||||
return new HubspotContactService(
|
||||
$container->get('HubspotClientService'),
|
||||
new HubspotMetaService($app->erp->GetTMP()),
|
||||
new ContactValidator(),
|
||||
$container->get('HubspotConfigurationService')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ContainerInterface $container
|
||||
*
|
||||
* @return HubspotClientService
|
||||
*/
|
||||
public static function onInitHubspotClientService(ContainerInterface $container)
|
||||
{
|
||||
return new HubspotClientService(
|
||||
$container->get('HubspotHttpClientService'),
|
||||
$container->get('HubspotConfigurationService')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return HubspotHttpClientService
|
||||
*/
|
||||
public static function onInitHubspotHttpClientService()
|
||||
{
|
||||
return new HubspotHttpClientService(30);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ContainerInterface $container
|
||||
*
|
||||
* @return HubspotConfigurationService
|
||||
*/
|
||||
public static function onInitHubspotConfigurationService(ContainerInterface $container)
|
||||
{
|
||||
/** @var ApplicationCore $app */
|
||||
$app = $container->get('LegacyApplication');
|
||||
|
||||
return new HubspotConfigurationService(
|
||||
$app->erp,
|
||||
new HubspotMetaService($app->erp->GetTMP()),
|
||||
$container->get('HubspotContactPropertyGateway'),
|
||||
$container->get('HubspotDealGateway'),
|
||||
$container->get('CountryGateway'),
|
||||
$container->get(StateGateway::class)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ContainerInterface $container
|
||||
*
|
||||
* @return HubspotContactGateway
|
||||
*/
|
||||
public static function onInitHubspotContactGateway(ContainerInterface $container)
|
||||
{
|
||||
return new HubspotContactGateway($container->get('Database'), $container->get('HubspotConfigurationService'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ContainerInterface $container
|
||||
*
|
||||
* @return HubspotPullContactsTask
|
||||
*/
|
||||
public static function onInitHubspotPullContactsTask(ContainerInterface $container)
|
||||
{
|
||||
/** @var ApplicationCore $app */
|
||||
$app = $container->get('LegacyApplication');
|
||||
|
||||
return new HubspotPullContactsTask(
|
||||
$container->get('HubspotContactService'),
|
||||
$container->get('Database'),
|
||||
new HubspotMetaService($app->erp->GetTMP()),
|
||||
$container->get('HubspotContactGateway'),
|
||||
$container->get('HubspotConfigurationService'),
|
||||
$container->get('HubspotEventService'),
|
||||
$container->get('CountryGateway'),
|
||||
new TaskMutexService($container->get('Database'))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ContainerInterface $container
|
||||
*
|
||||
* @return HubspotDealGateway
|
||||
*/
|
||||
public static function onInitHubspotDealGateway(ContainerInterface $container)
|
||||
{
|
||||
return new HubspotDealGateway($container->get('Database'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ContainerInterface $container
|
||||
*
|
||||
* @return HubspotDealService
|
||||
*/
|
||||
public static function onInitHubspotDealService(ContainerInterface $container)
|
||||
{
|
||||
/** @var ApplicationCore $app */
|
||||
$app = $container->get('LegacyApplication');
|
||||
|
||||
return new HubspotDealService(
|
||||
$container->get('HubspotClientService'),
|
||||
new HubspotMetaService($app->erp->GetTMP()),
|
||||
new DealValidator()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ContainerInterface $container
|
||||
*
|
||||
* @return HubspotContactPropertyService
|
||||
*/
|
||||
public static function onInitHubspotContactPropertyService(ContainerInterface $container)
|
||||
{
|
||||
return new HubspotContactPropertyService(
|
||||
$container->get('HubspotClientService'),
|
||||
$container->get('HubspotContactPropertyGateway'),
|
||||
$container->get('Database')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ContainerInterface $container
|
||||
*
|
||||
* @return HubspotContactPropertyGateway
|
||||
*/
|
||||
public static function onInitHubspotContactPropertyGateway(ContainerInterface $container)
|
||||
{
|
||||
return new HubspotContactPropertyGateway($container->get('Database'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ContainerInterface $container
|
||||
*
|
||||
* @return HubspotPullDealsTask
|
||||
*/
|
||||
public static function onInitHubspotPullDealsTask(ContainerInterface $container)
|
||||
{
|
||||
/** @var ApplicationCore $app */
|
||||
$app = $container->get('LegacyApplication');
|
||||
|
||||
return new HubspotPullDealsTask(
|
||||
$container->get('HubspotDealService'),
|
||||
$container->get('Database'),
|
||||
new HubspotMetaService($app->erp->GetTMP()),
|
||||
$container->get('HubspotDealGateway'),
|
||||
$container->get('HubspotConfigurationService'),
|
||||
$container->get('HubspotEventService'),
|
||||
$container->get('HubspotContactGateway'),
|
||||
new TaskMutexService($container->get('Database'))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ContainerInterface $container
|
||||
*
|
||||
* @return HubspotDealPropertyService
|
||||
*/
|
||||
public function onInitHubspotDealPropertyService(ContainerInterface $container)
|
||||
{
|
||||
return new HubspotDealPropertyService(
|
||||
$container->get('HubspotClientService'),
|
||||
$container->get('Database'),
|
||||
$container->get('HubspotContactPropertyGateway')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ContainerInterface $container
|
||||
*
|
||||
* @return HubspotProcessSchedulerTask
|
||||
*/
|
||||
public static function onInitHubspotProcessSchedulerTask(ContainerInterface $container)
|
||||
{
|
||||
return new HubspotProcessSchedulerTask(
|
||||
$container->get('HubspotRequestQueuesService'),
|
||||
new TaskMutexService($container->get('Database'))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ContainerInterface $container
|
||||
*
|
||||
* @return HubspotRequestQueuesGateway
|
||||
*/
|
||||
public static function onInitRequestQueuesGateway(ContainerInterface $container)
|
||||
{
|
||||
return new HubspotRequestQueuesGateway($container->get('Database'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ContainerInterface $container
|
||||
*
|
||||
* @return HubspotRequestQueuesService
|
||||
*/
|
||||
public static function onInitRequestQueuesService(ContainerInterface $container)
|
||||
{
|
||||
/** @var ApplicationCore $app */
|
||||
$app = $container->get('LegacyApplication');
|
||||
|
||||
return new HubspotRequestQueuesService(
|
||||
$container->get('HubspotRequestQueuesGateway'),
|
||||
$container->get('Database'),
|
||||
$app,
|
||||
$container->get('HubspotEventService')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ContainerInterface $container
|
||||
*
|
||||
* @return HubspotEventService
|
||||
*/
|
||||
public static function onInitHubspotEventService(ContainerInterface $container): HubspotEventService
|
||||
{
|
||||
return new HubspotEventService($container->get('Database'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ContainerInterface $container
|
||||
*
|
||||
* @return HubspotEngagementService
|
||||
*/
|
||||
public static function onInitHubspotEngagementService(ContainerInterface $container): HubspotEngagementService
|
||||
{
|
||||
return new HubspotEngagementService($container->get('HubspotClientService'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ContainerInterface $container
|
||||
*
|
||||
* @return HubspotPullEngagementsTask
|
||||
*/
|
||||
public static function onInitHubspotPullEngagementsTask(ContainerInterface $container): HubspotPullEngagementsTask
|
||||
{
|
||||
/** @var ApplicationCore $app */
|
||||
$app = $container->get('LegacyApplication');
|
||||
|
||||
return new HubspotPullEngagementsTask(
|
||||
$container->get('Database'),
|
||||
$container->get(HubspotEngagementService::class),
|
||||
new HubspotMetaService($app->erp->GetTMP()),
|
||||
$container->get('HubspotConfigurationService'),
|
||||
$container->get('HubspotEventService'),
|
||||
$container->get('HubspotContactGateway'),
|
||||
new TaskMutexService($container->get('Database'))
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\Hubspot\Exception;
|
||||
|
||||
final class HttpClientException extends HubspotException
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\Hubspot\Exception;
|
||||
|
||||
final class HubspotConfigurationServiceException extends HubspotException
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\Hubspot\Exception;
|
||||
|
||||
class HubspotContactGatewayNotFoundException extends HubspotException
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\Hubspot\Exception;
|
||||
|
||||
final class HubspotDealGatewayNotFoundException extends HubspotException
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\Hubspot\Exception;
|
||||
|
||||
use RuntimeException as SplRuntimeException;
|
||||
final class HubspotEngagementException extends SplRuntimeException
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\Hubspot\Exception;
|
||||
|
||||
use RuntimeException as SplRuntimeException;
|
||||
|
||||
class HubspotException extends SplRuntimeException implements HubspotExceptionInterface
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\Hubspot\Exception;
|
||||
|
||||
use Xentral\Core\Exception\ModuleExceptionInterface;
|
||||
|
||||
interface HubspotExceptionInterface extends ModuleExceptionInterface
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\Hubspot\Exception;
|
||||
|
||||
class MetaException extends HubspotException
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\Hubspot\Exception;
|
||||
|
||||
use BadMethodCallException as SplBadMethodCallException;
|
||||
|
||||
class SchedulerAdapterBadMethodException extends SplBadMethodCallException implements HubspotExceptionInterface
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,228 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\Hubspot;
|
||||
|
||||
use Xentral\Modules\Hubspot\Exception\HttpClientException;
|
||||
use Xentral\Modules\Hubspot\Exception\HubspotException;
|
||||
|
||||
final class HubspotClientService
|
||||
{
|
||||
|
||||
private $resource;
|
||||
|
||||
private $endPoints = [
|
||||
'allContacts' => '/contacts/v1/lists/all/contacts/all',
|
||||
'recentlyAddedContacts' => '/contacts/v1/lists/all/contacts/recent',
|
||||
'recentlyUpdatedContacts' => '/contacts/v1/lists/recently_updated/contacts/recent',
|
||||
'deleteContact' => '/contacts/v1/contact/vid/:contact_id',
|
||||
'updateContact' => '/contacts/v1/contact/vid/:vid/profile',
|
||||
'createContact' => '/contacts/v1/contact',
|
||||
'getContactById' => '/contacts/v1/contact/vid/:vid/profile',
|
||||
'createOrUpdateContact' => '/contacts/v1/contact/createOrUpdate/email/:contact_email',
|
||||
'createDeal' => '/deals/v1/deal/',
|
||||
'recentlyUpdatedDeals' => '/deals/v1/deal/recent/modified',
|
||||
'recentlyAddedDeals' => '/deals/v1/deal/recent/created',
|
||||
'allDeals' => '/deals/v1/deal/paged',
|
||||
'deleteDeal' => '/deals/v1/deal/:dealId',
|
||||
'updateDeal' => '/deals/v1/deal/:dealId',
|
||||
'getAllContactProperties' => '/properties/v1/contacts/properties',
|
||||
'getContactProperty' => '/properties/v1/contacts/properties/named/:property_name',
|
||||
'getCompanyProperty' => '/properties/v1/companies/properties/named/:property_name',
|
||||
'getPipelineProperties' => '/crm-pipelines/v1/pipelines/:object_type',
|
||||
'getDealById' => '/deals/v1/deal/:dealId',
|
||||
'getCompanyById' => '/companies/v2/companies/:companyId',
|
||||
'getRecentCompanies' => '/companies/v2/companies/recent/modified',
|
||||
'getCompanies' => '/companies/v2/companies/paged?properties=name&properties=website&properties=country&properties=zip&properties=address&properties=hs_lead_status&properties=city&properties=phone',
|
||||
'getCompanyContacts' => '/companies/v2/companies/:companyId/contacts',
|
||||
'addContactToCompany' => '/crm-associations/v1/associations',
|
||||
'deleteContactFromCompany' => '/crm-associations/v1/associations/delete',
|
||||
'createCompany' => '/companies/v2/companies',
|
||||
'updateCompany' => '/companies/v2/companies/:companyId',
|
||||
'createEngagement' => '/engagements/v1/engagements',
|
||||
'updateEngagement' => '/engagements/v1/engagements/:engagementId',
|
||||
'getRecentEngagements' => '/engagements/v1/engagements/recent/modified',
|
||||
'getHubspotOwner' => '/owners/v2/owners/:ownerId',
|
||||
|
||||
];
|
||||
|
||||
private $authMethod = 'key';
|
||||
|
||||
/** @var string|null $apiKey */
|
||||
private $apiKey;
|
||||
|
||||
/** @var HubspotHttpClientService $client */
|
||||
private $client;
|
||||
/**
|
||||
* @var HubspotConfigurationService
|
||||
*/
|
||||
private $confService;
|
||||
|
||||
public function __construct(HubspotHttpClientService $client, HubspotConfigurationService $confService, $apiKey = null)
|
||||
{
|
||||
$this->client = $client;
|
||||
$this->apiKey = $apiKey;
|
||||
$this->confService = $confService;
|
||||
}
|
||||
|
||||
/** @var string $apiUrl */
|
||||
private $apiUrl = 'https://api.hubapi.com%s';
|
||||
|
||||
/**
|
||||
* @param null $suffix
|
||||
* @param array $args
|
||||
*
|
||||
* @throws HubspotException
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getEndPoint($suffix = null, $args = [])
|
||||
{
|
||||
$resource = null;
|
||||
if (null === $suffix && !($resource = $this->getResource())) {
|
||||
throw new HubspotException('Endpoint suffix cannot be set');
|
||||
}
|
||||
|
||||
if ($resource !== null && !array_key_exists($resource, $this->endPoints)) {
|
||||
throw new HubspotException('Undefined resource endpoint');
|
||||
}
|
||||
|
||||
$suffixUrl = null === $suffix ? $this->endPoints[$resource] : $suffix;
|
||||
$url = sprintf($this->apiUrl, $suffixUrl);
|
||||
if ($this->authMethod === 'key') {
|
||||
$apiKey = null === $this->apiKey ? $this->getConfApiKey() : $this->apiKey;
|
||||
$url .= strpos($url, '?') === false? '?hapikey=' . $apiKey : '&hapikey=' . $apiKey;
|
||||
}
|
||||
if (!empty($args)) {
|
||||
preg_match_all('/:[a-zA-Z0-9._-]+/', $url, $match);
|
||||
if (!empty($match) && !empty($match[0])) {
|
||||
$url = str_replace($match[0], $args, $url);
|
||||
}
|
||||
}
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $resource
|
||||
*
|
||||
* @return HubspotClientService
|
||||
*/
|
||||
public function setResource($resource)
|
||||
{
|
||||
$this->resource = $resource;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getResource()
|
||||
{
|
||||
return $this->resource;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @param array $endPointArgs
|
||||
*
|
||||
* @return HubspotHttpResponseService
|
||||
*/
|
||||
public function read($data = [], $endPointArgs = [])
|
||||
{
|
||||
return $this->client->get($this->getEndPoint(null, $endPointArgs), $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return false|string|null
|
||||
*/
|
||||
private function getConfApiKey()
|
||||
{
|
||||
return $this->confService->getDecryptedConfiguration(HubspotConfigurationService::HUBSPOT_SALT_CONF_NAME);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @param array $endPointArgs
|
||||
*
|
||||
* @return HubspotHttpResponseService
|
||||
*/
|
||||
public function post($data = [], $endPointArgs = [])
|
||||
{
|
||||
return $this->client->post($this->getEndPoint(null, $endPointArgs), $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @param array $endPointArgs
|
||||
*
|
||||
* @return HubspotHttpResponseService
|
||||
*/
|
||||
public function delete($data = [], $endPointArgs = [])
|
||||
{
|
||||
return $this->client->delete($this->getEndPoint(null, $endPointArgs), $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @param array $endPointArgs
|
||||
*
|
||||
* @return HubspotHttpResponseService
|
||||
*/
|
||||
public function put($data = [], $endPointArgs = [])
|
||||
{
|
||||
return $this->client->put($this->getEndPoint(null, $endPointArgs), $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @param array $endPointArgs
|
||||
*
|
||||
* @throws HubspotException
|
||||
*
|
||||
* @return HubspotHttpResponseService
|
||||
*/
|
||||
public function patch($data = [], $endPointArgs = []): HubspotHttpResponseService
|
||||
{
|
||||
return $this->client->patch($this->getEndPoint(null, $endPointArgs), $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @param array $endPointArgs
|
||||
*
|
||||
* @return HubspotHttpResponseService
|
||||
*/
|
||||
public function get($data = [], $endPointArgs = []): HubspotHttpResponseService
|
||||
{
|
||||
return $this->read($data, $endPointArgs);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $resource
|
||||
* @param string $type
|
||||
* @param array $data
|
||||
* @param array $endPointArgs
|
||||
*
|
||||
* @throws HubspotException
|
||||
*
|
||||
* @return HubspotHttpResponseService
|
||||
*/
|
||||
public function apiCall(
|
||||
string $resource,
|
||||
string $type,
|
||||
array $data = [],
|
||||
array $endPointArgs = []
|
||||
) : HubspotHttpResponseService
|
||||
{
|
||||
if (!method_exists($this, $type)) {
|
||||
throw new HttpClientException(sprintf('Methode ::%s is not yet implemented !', $type));
|
||||
}
|
||||
$this->resource = $resource;
|
||||
return $this->client->{strtolower($type)}($this->getEndPoint(null, $endPointArgs), $data);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,623 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\Hubspot;
|
||||
|
||||
use DateInterval;
|
||||
use DateTime;
|
||||
use erpAPI;
|
||||
use Exception;
|
||||
use Xentral\Modules\Country\Gateway\CountryGateway;
|
||||
use Xentral\Modules\Country\Gateway\StateGateway;
|
||||
use Xentral\Modules\Hubspot\Exception\HubspotConfigurationServiceException;
|
||||
use Xentral\Modules\Hubspot\Exception\HubspotException;
|
||||
|
||||
class HubspotConfigurationService
|
||||
{
|
||||
public const HUBSPOT_SALT_CONF_NAME = 'hubspot_configuration_salt';
|
||||
public const HUBSPOT_SETTING_CONF_NAME = 'hubspot_settings';
|
||||
|
||||
private static $_defaultSettings = [
|
||||
'hs_sync_deals' => true,
|
||||
'hs_sync_addresses' => true,
|
||||
];
|
||||
|
||||
/** @var erpAPI $erp */
|
||||
private $erp;
|
||||
/**
|
||||
* @var HubspotMetaService
|
||||
*/
|
||||
private $meta;
|
||||
/**
|
||||
* @var HubspotContactPropertyGateway
|
||||
*/
|
||||
private $propertyGateway;
|
||||
|
||||
/** @var HubspotDealGateway $hubspotDealGateway */
|
||||
private $hubspotDealGateway;
|
||||
|
||||
/** @var CountryGateway $countryGateway */
|
||||
private $countryGateway;
|
||||
|
||||
/** @var StateGateway $stateGateway */
|
||||
private $stateGateway;
|
||||
|
||||
/**
|
||||
* @param erpAPI $erp
|
||||
* @param HubspotMetaService $meta
|
||||
* @param HubspotContactPropertyGateway $propertyGateway
|
||||
* @param HubspotDealGateway $hubspotDealGateway
|
||||
* @param CountryGateway $countryGateway
|
||||
* @param StateGateway $stateGateway
|
||||
*/
|
||||
public function __construct(
|
||||
erpAPI $erp,
|
||||
HubspotMetaService $meta,
|
||||
HubspotContactPropertyGateway $propertyGateway,
|
||||
HubspotDealGateway $hubspotDealGateway,
|
||||
CountryGateway $countryGateway,
|
||||
StateGateway $stateGateway
|
||||
) {
|
||||
$this->erp = $erp;
|
||||
$this->meta = $meta;
|
||||
$this->meta->setName('conf');
|
||||
$this->propertyGateway = $propertyGateway;
|
||||
$this->hubspotDealGateway = $hubspotDealGateway;
|
||||
$this->countryGateway = $countryGateway;
|
||||
$this->stateGateway = $stateGateway;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param string $value
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function trySetConfiguration($name, $value)
|
||||
{
|
||||
if (empty($name) || !is_string($value)) {
|
||||
throw new HubspotConfigurationServiceException('Cannot set Configuration');
|
||||
}
|
||||
|
||||
$this->erp->SetKonfigurationValue($name, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
*
|
||||
* @return array|mixed|string|null
|
||||
*/
|
||||
public function tryGetConfiguration($name)
|
||||
{
|
||||
if (empty($name)) {
|
||||
throw new HubspotConfigurationServiceException('Cannot Get Configuration');
|
||||
}
|
||||
|
||||
return $this->erp->GetKonfiguration($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param string $value
|
||||
*/
|
||||
public function setEncryptedConfiguration($name, $value)
|
||||
{
|
||||
if (empty($name) || !is_string($value)) {
|
||||
throw new HubspotConfigurationServiceException('Cannot set Configuration');
|
||||
}
|
||||
$encValue = $this->encrypt($value);
|
||||
$this->trySetConfiguration($name, $encValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
*
|
||||
* @return false|string|null
|
||||
*/
|
||||
public function getDecryptedConfiguration($name)
|
||||
{
|
||||
if (empty($name)) {
|
||||
throw new HubspotConfigurationServiceException('Cannot Get Configuration');
|
||||
}
|
||||
|
||||
return $this->decrypt($this->tryGetConfiguration($name));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $string
|
||||
* @param string $sCipher
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function encrypt($string, $sCipher = 'AES-256-CBC')
|
||||
{
|
||||
if (empty($string)) {
|
||||
return '';
|
||||
}
|
||||
if (null === $this->getNonceSalt()) {
|
||||
return $string;
|
||||
}
|
||||
$key = hash('sha256', $this->getNonceSalt());
|
||||
$ivlen = openssl_cipher_iv_length($sCipher);
|
||||
$iv = openssl_random_pseudo_bytes($ivlen);
|
||||
$ciphertext_raw = openssl_encrypt($string, $sCipher, $key, OPENSSL_RAW_DATA, $iv);
|
||||
$hmac = hash_hmac('sha256', $ciphertext_raw, $key, $as_binary = true);
|
||||
|
||||
return base64_encode($iv . $hmac . $ciphertext_raw);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $string
|
||||
* @param string $sCipher
|
||||
*
|
||||
* @return false|string|null
|
||||
*/
|
||||
protected function decrypt($string, $sCipher = 'AES-256-CBC')
|
||||
{
|
||||
if (empty($string) || !$this->isBase64Encoded($string)) {
|
||||
return '';
|
||||
}
|
||||
if (null === $this->getNonceSalt()) {
|
||||
return $this->isBase64Encoded($string) ? null : $string;
|
||||
}
|
||||
$enc = base64_decode($string);
|
||||
$key = hash('sha256', $this->getNonceSalt());
|
||||
$ivlen = openssl_cipher_iv_length($sCipher);
|
||||
$iv = substr($enc, 0, $ivlen);
|
||||
$hmac = substr($enc, $ivlen, $sha2len = 32);
|
||||
$ciphertext_raw = substr($enc, $ivlen + $sha2len);
|
||||
$original_plaintext = openssl_decrypt($ciphertext_raw, $sCipher, $key, OPENSSL_RAW_DATA, $iv);
|
||||
$calcmac = hash_hmac('sha256', $ciphertext_raw, $key, true);
|
||||
|
||||
return hash_equals($hmac, $calcmac) ? $original_plaintext : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $string
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function isBase64Encoded($string)
|
||||
{
|
||||
return base64_encode(base64_decode($string)) === $string;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return false|string|null
|
||||
*/
|
||||
private function generateSecureSalt()
|
||||
{
|
||||
return password_hash(uniqid(mt_rand(), true), PASSWORD_BCRYPT);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $force
|
||||
*
|
||||
* @return false|int
|
||||
*/
|
||||
public function createSalt($force = false)
|
||||
{
|
||||
if ($force === true) {
|
||||
$this->meta->delete();
|
||||
}
|
||||
if ($this->meta->exists() && $this->meta->keyExists('nonce_salt')) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return $this->meta->save(['nonce_salt' => $this->generateSecureSalt()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string|null
|
||||
*/
|
||||
private function getNonceSalt()
|
||||
{
|
||||
$data = $this->meta->get();
|
||||
|
||||
return array_key_exists('nonce_salt', $data) ? $data['nonce_salt'] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param HubspotHttpResponseService $response
|
||||
*
|
||||
* @throws HubspotException
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function formatAddressByResponse(HubspotHttpResponseService $response): array
|
||||
{
|
||||
if ($response->getStatusCode() !== 200) {
|
||||
throw new HubSpotException($response->getError());
|
||||
}
|
||||
$contact = $response->getJson();
|
||||
$properties = $contact['properties'];
|
||||
$hubspotContact = array_combine(array_keys($properties), array_column($properties, 'value'));
|
||||
$hubspotOwnerId = (int)array_key_exists(
|
||||
'hubspot_owner_id',
|
||||
$hubspotContact
|
||||
) ? $hubspotContact['hubspot_owner_id'] : 0;
|
||||
|
||||
$data = [
|
||||
'lead' => 1,
|
||||
'typ' => 'herr',
|
||||
'sprache' => 'deutsch',
|
||||
'name' => sprintf(
|
||||
'%s %s',
|
||||
empty($hubspotContact['firstname']) ? 'Hubspot - ' : $hubspotContact['firstname'],
|
||||
empty($hubspotContact['lastname']) ? $hubspotContact['email'] : $hubspotContact['lastname']
|
||||
),
|
||||
'vorname' => empty($hubspotContact['firstname']) ? 'Hubspot - ' : $hubspotContact['firstname'],
|
||||
'nachname' => empty($hubspotContact['lastname']) ? $hubspotContact['email'] : $hubspotContact['lastname'],
|
||||
'ort' => empty($hubspotContact['city']) ? '' : $hubspotContact['city'],
|
||||
'plz' => empty($hubspotContact['zip']) ? '' : $hubspotContact['zip'],
|
||||
'telefon' => empty($hubspotContact['phone']) ? '' : $hubspotContact['phone'],
|
||||
'email' => $hubspotContact['email'],
|
||||
'kundenfreigabe' => 1,
|
||||
'waehrung' => 'EUR',
|
||||
'strasse' => empty($hubspotContact['address']) ? '' : $hubspotContact['address'],
|
||||
'internetseite' => empty($hubspotContact['website']) ? '' : $hubspotContact['website'],
|
||||
'hubspot_owner_id' => $hubspotOwnerId,
|
||||
];
|
||||
$country = empty($hubspotContact['country']) ? 'DE' : $hubspotContact['country'];
|
||||
if (!empty($country)) {
|
||||
$countryDb = $this->countryGateway->findByName($country);
|
||||
if (!empty($countryDb)) {
|
||||
$country = $countryDb['iso2_code'];
|
||||
}
|
||||
}
|
||||
$data['land'] = $country;
|
||||
|
||||
$state = empty($hubspotContact['state']) ? '' : $hubspotContact['state'];
|
||||
if (!empty($state) && strlen($country) === 2) {
|
||||
$stateDb = $this->stateGateway->findByNameAndIso2CountryCode($state, $country);
|
||||
if (!empty($stateDb)) {
|
||||
$state = $stateDb['iso2_code'];
|
||||
}
|
||||
}
|
||||
$data['bundesstaat'] = $state;
|
||||
|
||||
try {
|
||||
$leadFields = $this->matchSelectedAddressFreeField();
|
||||
$lrField = $leadFields['hubspot_lr_field'];
|
||||
$lsField = $leadFields['hubspot_ls_field'];
|
||||
$data[$lsField] = empty($hubspotContact['hs_lead_status']) ? '' : $hubspotContact['hs_lead_status'];
|
||||
$data[$lrField] = empty($hubspotContact['lifecyclestage']) ? '' : $hubspotContact['lifecyclestage'];
|
||||
} catch (HubspotException $exception) {
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws HubspotException
|
||||
* @return array
|
||||
*/
|
||||
public function matchSelectedAddressFreeField()
|
||||
{
|
||||
$hFields = [];
|
||||
$asAddressFreeFieldValues = $this->propertyGateway->getConfiguredFreeAddressFieldValues();
|
||||
$hsConfFields = [
|
||||
'hubspot_lr_field' => $this->tryGetConfiguration('hubspot_lr_field'),
|
||||
'hubspot_ls_field' => $this->tryGetConfiguration('hubspot_ls_field'),
|
||||
];
|
||||
foreach ($asAddressFreeFieldValues as $fieldName) {
|
||||
if (in_array('adresse' . $fieldName, $hsConfFields)) {
|
||||
$hFields[array_search('adresse' . $fieldName, $hsConfFields)] = $fieldName;
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($hFields)) {
|
||||
throw new HubSpotException('Lead-Status/Lifecycle fields cannot be matched');
|
||||
}
|
||||
|
||||
return $hFields;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $address
|
||||
*
|
||||
* @throws HubspotException
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function formatAddressToHubspotContact(array $address): array
|
||||
{
|
||||
if (empty($address)) {
|
||||
throw new HubSpotException('Address is invalid');
|
||||
}
|
||||
$leadFields = $this->matchSelectedAddressFreeField();
|
||||
$lrField = $leadFields['hubspot_lr_field'];
|
||||
$lsField = $leadFields['hubspot_ls_field'];
|
||||
|
||||
$firstName = empty($address['vorname']) ? '' : $address['vorname'];
|
||||
$lastName = empty($address['nachname']) ? '' : $address['nachname'];
|
||||
|
||||
if (empty($lastName) && (empty($firstName) || $firstName !== $address['name'])) {
|
||||
$lastName = $address['name'];
|
||||
}
|
||||
|
||||
$data = [
|
||||
'email' => $address['email'],
|
||||
'firstname' => $firstName,
|
||||
'lastname' => $lastName,
|
||||
'website' => $address['internetseite'],
|
||||
'phone' => $address['telefon'],
|
||||
'address' => $address['strasse'],
|
||||
'city' => $address['ort'],
|
||||
'state' => $address['bundesstaat'],
|
||||
'zip' => $address['plz'],
|
||||
'hs_lead_status' => $address[$lsField],
|
||||
'lifecyclestage' => $address[$lrField],
|
||||
];
|
||||
|
||||
$iso2CountryCode = $address['land'];
|
||||
if (!empty($iso2CountryCode)) {
|
||||
$countryDb = $this->countryGateway->findByIso2Code($iso2CountryCode);
|
||||
if (!empty($countryDb)) {
|
||||
$country = $countryDb['name_de'];
|
||||
$data['country'] = $country;
|
||||
}
|
||||
}
|
||||
|
||||
$iso2State = $address['bundesstaat'];
|
||||
if (!empty($iso2State) && strlen($iso2CountryCode) === 2) {
|
||||
$stateDb = $this->stateGateway->findByIso2CodeAndIso2CountryCode($iso2State, $iso2CountryCode);
|
||||
if (!empty($stateDb)) {
|
||||
$iso2State = $stateDb['name_de'];
|
||||
}
|
||||
}
|
||||
$data['state'] = $iso2State;
|
||||
|
||||
if (array_key_exists('typ', $address) && !empty($address['typ'])) {
|
||||
$data['salutation'] = $address['typ'];
|
||||
|
||||
if ($address['typ'] === 'firma') {
|
||||
if (array_key_exists('numberofemployees', $address) &&
|
||||
!empty($address['numberofemployees'])) {
|
||||
$data['numberofemployees'] = $address['numberofemployees'];
|
||||
}
|
||||
|
||||
$settings = $this->getSettings();
|
||||
$defaultCustomFields = array_key_exists('hubspot_address_free_fields', $settings) ?
|
||||
$settings['hubspot_address_free_fields'] : [];
|
||||
if (!empty($defaultCustomFields)) {
|
||||
foreach ($defaultCustomFields as $property => $systemField) {
|
||||
$data[$property] = $address[sprintf('xthubspot_%s', $property)];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param HubspotHttpResponseService $response
|
||||
*
|
||||
* @throws Exception
|
||||
* @return array
|
||||
*/
|
||||
public function formatDealByResponse(HubspotHttpResponseService $response)
|
||||
{
|
||||
if ($response->getStatusCode() === 200) {
|
||||
$deal = $response->getJson();
|
||||
$properties = $deal['properties'];
|
||||
|
||||
$hDeal = array_combine(array_keys($properties), array_column($properties, 'value'));
|
||||
$dealStage = $this->propertyGateway->getMappingByValueAndType($hDeal['dealstage'], 'deals');
|
||||
|
||||
return [
|
||||
'bezeichnung' => $hDeal['dealname'],
|
||||
'datum_angelegt' => date('Y-m-d', $hDeal['createdate'] / 1000),
|
||||
'zeit_angelegt' => date('H:i:s', $hDeal['createdate'] / 1000),
|
||||
'datum_erinnerung' => $this->getTimeByDays($hDeal['days_to_close'])->format('Y-m-d'),
|
||||
'zeit_erinnerung' => $this->getTimeByDays($hDeal['days_to_close'])->format('H:i:s'),
|
||||
'betrag' => array_key_exists('amount', $hDeal) ? (float)$hDeal['amount'] : 0.00,
|
||||
'stages' => !empty($dealStage['wiedervorlage_stage_id']) ? $dealStage['wiedervorlage_stage_id'] : 0,
|
||||
];
|
||||
}
|
||||
throw new HubSpotException($response->getError());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $resubmission
|
||||
*
|
||||
* @throws Exception
|
||||
* @return array
|
||||
*/
|
||||
public function formatResubmissionToHubspotDeal($resubmission)
|
||||
{
|
||||
if (is_array($resubmission) && !empty($resubmission)) {
|
||||
$oCloseDate = null;
|
||||
if (!empty($resubmission['datum_erinnerung']) && !empty($resubmission['zeit_erinnerung'])) {
|
||||
$closeDate = $resubmission['datum_erinnerung'] . ' ' . $resubmission['zeit_erinnerung'];
|
||||
$oCloseDate = new DateTime($closeDate);
|
||||
}
|
||||
$mapping = $this->hubspotDealGateway->getMappingStageByResubmissionStageId($resubmission['stages']);
|
||||
|
||||
return [
|
||||
'dealname' => $resubmission['bezeichnung'],
|
||||
'dealstage' => !empty($mapping) ? $mapping['value'] : null,
|
||||
'amount' => empty($resubmission['betrag']) ? 0.00 : $resubmission['betrag'],
|
||||
'pipeline' => 'default',
|
||||
'closedate' => null !== $oCloseDate ? $oCloseDate->getTimestamp() * 1000 : 0,
|
||||
];
|
||||
}
|
||||
throw new HubSpotException('Resubmission is invalid');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $days
|
||||
*
|
||||
* @throws Exception
|
||||
* @return DateTime
|
||||
*/
|
||||
private function getTimeByDays($days)
|
||||
{
|
||||
$date = new DateTime('now');
|
||||
$interval = sprintf('P%dD', (int)$days);
|
||||
$date->add(new DateInterval($interval));
|
||||
|
||||
return $date;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $settings
|
||||
*/
|
||||
public function setSettings($settings = [])
|
||||
{
|
||||
$this->trySetConfiguration(
|
||||
static::HUBSPOT_SETTING_CONF_NAME,
|
||||
json_encode($settings, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws HubspotConfigurationServiceException
|
||||
* @return array
|
||||
*/
|
||||
public function getSettings()
|
||||
{
|
||||
$settingsRaw = $this->tryGetConfiguration(static::HUBSPOT_SETTING_CONF_NAME);
|
||||
if (empty($settingsRaw)) {
|
||||
return static::$_defaultSettings;
|
||||
}
|
||||
if (($settings = json_decode($settingsRaw, true)) !== null
|
||||
&& (json_last_error() === JSON_ERROR_NONE)) {
|
||||
if (empty($settings)) {
|
||||
return static::$_defaultSettings;
|
||||
}
|
||||
|
||||
return $settings;
|
||||
}
|
||||
throw new HubspotConfigurationServiceException(json_last_error_msg());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $contactId
|
||||
*
|
||||
* @throws HubspotConfigurationServiceException
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function addContactToGroup(int $contactId = 0): void
|
||||
{
|
||||
$defaultSettings = $this->getSettings();
|
||||
|
||||
$contactGrpId = array_key_exists('hs_contact_grp', $defaultSettings) ? $defaultSettings['hs_contact_grp'] : 0;
|
||||
if (!empty($contactGrpId)) {
|
||||
$this->erp->AddRolleZuAdresse($contactId, 'Mitglied', 'von', 'Gruppe', $contactGrpId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param HubspotHttpResponseService $response
|
||||
*
|
||||
* @throws HubspotException
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function formatCompanyByResponse(HubspotHttpResponseService $response): array
|
||||
{
|
||||
if ($response->getStatusCode() !== 200) {
|
||||
throw new HubSpotException($response->getError());
|
||||
}
|
||||
$contact = $response->getJson();
|
||||
$properties = $contact['properties'];
|
||||
|
||||
$hubspotContact = array_combine(array_keys($properties), array_column($properties, 'value'));
|
||||
$hubspotOwnerId = (int)array_key_exists(
|
||||
'hubspot_owner_id',
|
||||
$hubspotContact
|
||||
) ? $hubspotContact['hubspot_owner_id'] : 0;
|
||||
|
||||
$data = [
|
||||
'typ' => 'firma',
|
||||
'sprache' => 'deutsch',
|
||||
'name' => empty($hubspotContact['name']) ? 'Hubspot - Company' : $hubspotContact['name'],
|
||||
'ort' => empty($hubspotContact['city']) ? '' : $hubspotContact['city'],
|
||||
'plz' => empty($hubspotContact['zip']) ? '' : $hubspotContact['zip'],
|
||||
'telefon' => empty($hubspotContact['phone']) ? '' : $hubspotContact['phone'],
|
||||
'kundenfreigabe' => 1,
|
||||
'waehrung' => 'EUR',
|
||||
'strasse' => empty($hubspotContact['address']) ? '' : $hubspotContact['address'],
|
||||
'internetseite' => empty($hubspotContact['website']) ? '' : $hubspotContact['website'],
|
||||
'hubspot_owner_id' => $hubspotOwnerId,
|
||||
];
|
||||
$country = empty($hubspotContact['country']) ? 'DE' : $hubspotContact['country'];
|
||||
|
||||
if (!empty($country)) {
|
||||
$countryDb = $this->countryGateway->findByName($country);
|
||||
if (!empty($countryDb)) {
|
||||
$country = $countryDb['iso2_code'];
|
||||
}
|
||||
}
|
||||
$data['land'] = $country;
|
||||
|
||||
$state = empty($hubspotContact['state']) ? '' : $hubspotContact['state'];
|
||||
if (!empty($state) && strlen($country) === 2) {
|
||||
$stateDb = $this->stateGateway->findByNameAndIso2CountryCode($state, $country);
|
||||
if (!empty($stateDb)) {
|
||||
$state = $stateDb['iso2_code'];
|
||||
}
|
||||
}
|
||||
$data['bundesstaat'] = $state;
|
||||
|
||||
try {
|
||||
$leadFields = $this->matchSelectedAddressFreeField();
|
||||
$lrField = $leadFields['hubspot_lr_field'];
|
||||
$lsField = $leadFields['hubspot_ls_field'];
|
||||
$data[$lsField] = empty($hubspotContact['hs_lead_status']) ? '' : $hubspotContact['hs_lead_status'];
|
||||
$data[$lrField] = empty($hubspotContact['lifecyclestage']) ? '' : $hubspotContact['lifecyclestage'];
|
||||
} catch (HubspotException $exception) {
|
||||
}
|
||||
|
||||
$numberOfEmployeesField = $this->tryGetConfiguration('hubspot_numberofemployees_field');
|
||||
if (!empty($numberOfEmployeesField)) {
|
||||
$fieldName = str_replace('adresse', '', $numberOfEmployeesField);
|
||||
$numberOfEmployees = empty($hubspotContact['numberofemployees']) ? 0 : $hubspotContact['numberofemployees'];
|
||||
$data[$fieldName] = $numberOfEmployees;
|
||||
}
|
||||
|
||||
$settings = $this->getSettings();
|
||||
$defaultCustomFields = array_key_exists('hubspot_address_free_fields', $settings) ?
|
||||
$settings['hubspot_address_free_fields'] : [];
|
||||
if (!empty($defaultCustomFields)) {
|
||||
foreach ($defaultCustomFields as $property => $systemField) {
|
||||
$fieldName = str_replace('adresse', '', $systemField);
|
||||
$data[$fieldName] = $hubspotContact[$property];
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $customFreeField
|
||||
* @param array $fieldConfig
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setSystemFreeField(string $customFreeField, array $fieldConfig): void
|
||||
{
|
||||
$label = $fieldConfig['label'];
|
||||
$type = $fieldConfig['fieldType'];
|
||||
$value = $fieldConfig['options'];
|
||||
$customFreeFieldValue = $label . '|' . implode('|', $value);
|
||||
$this->erp->FirmendatenSet($customFreeField, $customFreeFieldValue);
|
||||
$this->erp->FirmendatenSet($customFreeField . 'typ', $type);
|
||||
$this->erp->FirmendatenSet($customFreeField . 'spalte', '1');
|
||||
$this->erp->Firmendaten($customFreeField);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $customFreeField
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function unsetSystemFreeField(string $customFreeField): void
|
||||
{
|
||||
$this->erp->FirmendatenSet($customFreeField, '');
|
||||
$this->erp->FirmendatenSet($customFreeField . 'typ', '');
|
||||
$this->erp->FirmendatenSet($customFreeField . 'spalte', '');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,223 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\Hubspot;
|
||||
|
||||
use Xentral\Components\Database\Database;
|
||||
|
||||
final class HubspotContactGateway
|
||||
{
|
||||
/** @var Database $db */
|
||||
private $db;
|
||||
/**
|
||||
* @var HubspotConfigurationService
|
||||
*/
|
||||
private $configurationService;
|
||||
|
||||
/**
|
||||
* @param Database $db
|
||||
* @param HubspotConfigurationService $configurationService
|
||||
*/
|
||||
public function __construct(Database $db, HubspotConfigurationService $configurationService)
|
||||
{
|
||||
$this->db = $db;
|
||||
$this->configurationService = $configurationService;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $hsContactId
|
||||
* @param null|string $type
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getMappingByHubspotId(int $hsContactId, ?string $type = 'address'): array
|
||||
{
|
||||
$sql = '
|
||||
SELECT
|
||||
h.id,
|
||||
h.created_at,
|
||||
h.data,
|
||||
h.address_id,
|
||||
h.type
|
||||
FROM `hubspot_contacts` AS `h` WHERE h.hidden = 0 AND h.hs_contact_id = :id';
|
||||
$where = ['id' => $hsContactId];
|
||||
|
||||
if ($type !== null) {
|
||||
$sql .= ' AND h.type = :type';
|
||||
$where['type'] = $type;
|
||||
}
|
||||
|
||||
return $this->db->fetchRow($sql, $where);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $addressId
|
||||
* @param string $type
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getMappingByAddressId(int $addressId, string $type = 'address'): array
|
||||
{
|
||||
return $this->db->fetchRow(
|
||||
'SELECT
|
||||
h.id,
|
||||
h.created_at,
|
||||
h.data,
|
||||
h.hs_contact_id
|
||||
FROM `hubspot_contacts` AS `h` WHERE h.hidden = 0 AND h.address_id = :id AND h.type = :type',
|
||||
['id' => $addressId, 'type' => $type]
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param int $addressId
|
||||
* @param bool $withStatusField
|
||||
*
|
||||
* @throws Exception\HubspotException
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getAddressById(int $addressId, bool $withStatusField = false): array
|
||||
{
|
||||
$placeHolder = '';
|
||||
if ($withStatusField === true) {
|
||||
$leadFields = $this->configurationService->matchSelectedAddressFreeField();
|
||||
$lrField = $leadFields['hubspot_lr_field'];
|
||||
$lsField = $leadFields['hubspot_ls_field'];
|
||||
$placeHolder = ",a.`{$lrField}`, a.`{$lsField}`";
|
||||
}
|
||||
|
||||
$numberOfEmployeesField = $this->configurationService->tryGetConfiguration('hubspot_numberofemployees_field');
|
||||
|
||||
if (!empty($numberOfEmployeesField)) {
|
||||
$fieldName = str_replace('adresse', '', $numberOfEmployeesField);
|
||||
$placeHolder .= ",a.`{$fieldName}` AS numberofemployees";
|
||||
}
|
||||
|
||||
$settings = $this->configurationService->getSettings();
|
||||
$defaultCustomFields = array_key_exists('hubspot_address_free_fields', $settings) ?
|
||||
$settings['hubspot_address_free_fields'] : [];
|
||||
if (!empty($defaultCustomFields)) {
|
||||
foreach ($defaultCustomFields as $defaultCustomField => $systemField) {
|
||||
$fieldName = str_replace('adresse', '', $systemField);
|
||||
$placeHolder .= ",a.`{$fieldName}` AS `xthubspot_{$defaultCustomField}`";
|
||||
}
|
||||
}
|
||||
|
||||
$sql = 'SELECT
|
||||
a.id,
|
||||
a.`lead`,
|
||||
a.typ,
|
||||
a.sprache,
|
||||
a.name,
|
||||
a.vorname,
|
||||
a.nachname,
|
||||
a.land,
|
||||
a.ort,
|
||||
a.plz,
|
||||
a.bundesstaat,
|
||||
a.telefon,
|
||||
a.strasse,
|
||||
a.vertrieb,
|
||||
a.email %s FROM `adresse` AS `a` WHERE a.geloescht = 0 AND a.id = :id';
|
||||
|
||||
return $this->db->fetchRow(sprintf($sql, $placeHolder), ['id' => $addressId]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $hsContactId
|
||||
* @param array $types
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hubspotContactExists(int $hsContactId, array $types = []): bool
|
||||
{
|
||||
$sql = '
|
||||
SELECT
|
||||
h.id
|
||||
FROM `hubspot_contacts` AS `h` WHERE h.hidden = 0 AND h.hs_contact_id = :id';
|
||||
$where = ['id' => $hsContactId];
|
||||
|
||||
if (!empty($types)) {
|
||||
$sqlType = implode("','", $types);
|
||||
$sql .= ' AND h.type IN(:type)';
|
||||
$where['type'] = $sqlType;
|
||||
}
|
||||
|
||||
return !empty($this->db->fetchValue($sql, $where));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $contactPersonId
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getContactPersonData(int $contactPersonId): array
|
||||
{
|
||||
$sql = 'SELECT
|
||||
ap.id,
|
||||
ap.adresse AS address_id,
|
||||
ap.typ,
|
||||
ap.sprache,
|
||||
ap.name,
|
||||
ap.vorname,
|
||||
ap.bereich,
|
||||
ap.land,
|
||||
ap.ort,
|
||||
ap.plz,
|
||||
ap.strasse,
|
||||
ap.telefon,
|
||||
ap.email FROM `ansprechpartner` AS `ap` WHERE ap.geloescht = 0 AND ap.id = :id';
|
||||
|
||||
return $this->db->fetchRow($sql, ['id' => $contactPersonId]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $contactPersonId
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getHubspotMappingByPersonId(int $contactPersonId): array
|
||||
{
|
||||
$sql = 'SELECT hc.hs_contact_id AS `company_id`,
|
||||
(SELECT `hs_contact_id` FROM `hubspot_contacts` WHERE `address_id` = :cid) AS `contact_id`
|
||||
FROM `ansprechpartner` AS `ap`
|
||||
JOIN `hubspot_contacts` AS `hc` ON(ap.adresse = hc.address_id AND hc.type = :type)
|
||||
WHERE ap.id = :cid';
|
||||
|
||||
return $this->db->fetchRow($sql, ['cid' => $contactPersonId, 'type' => 'company']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $noteId
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getAddressInfoByNoteId(int $noteId): array
|
||||
{
|
||||
$sql = 'SELECT d.adresse_to AS `address_id`,
|
||||
a.typ AS `type`,
|
||||
a.name, d.betreff AS `object`,
|
||||
d.content FROM `dokumente` AS `d`
|
||||
JOIN `adresse` AS `a` ON(d.adresse_to = a.id)
|
||||
WHERE d.`id` = :note_id AND d.typ = :type';
|
||||
|
||||
return $this->db->fetchRow($sql, ['note_id' => $noteId, 'type' => 'notiz']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $companyId
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hubspotSaleStaffExists(int $companyId): bool
|
||||
{
|
||||
$sql = '
|
||||
SELECT
|
||||
h.id
|
||||
FROM `hubspot_contacts` AS `h` WHERE h.hidden = 0 AND h.data = :company AND h.type = :type';
|
||||
$where = ['company' => (string)$companyId, 'type' => 'sale_staff'];
|
||||
|
||||
return !empty($this->db->fetchValue($sql, $where));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\Hubspot;
|
||||
|
||||
use Xentral\Components\Database\Database;
|
||||
|
||||
final class HubspotContactPropertyGateway
|
||||
{
|
||||
/** @var Database $db */
|
||||
private $db;
|
||||
|
||||
/**
|
||||
* @param Database $db
|
||||
*/
|
||||
public function __construct(Database $db)
|
||||
{
|
||||
$this->db = $db;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $type
|
||||
* @param bool $isSystem
|
||||
* @param string $scope
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getLeadsByType(string $type, bool $isSystem = false, string $scope = 'contact')
|
||||
{
|
||||
return $this->db->fetchAssoc(
|
||||
'SELECT
|
||||
h.id,
|
||||
h.created_at,
|
||||
h.label,
|
||||
h.value,
|
||||
h.type,
|
||||
h.wiedervorlage_stage_id
|
||||
FROM `hs_mapping_leads` AS `h` WHERE h.type = :type AND h.is_system = :system and h.setting_scope = :scope',
|
||||
['type' => $type, 'system' => (int)$isSystem, 'scope' => $scope]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $value
|
||||
*
|
||||
* @param string $type
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getMappingByValueAndType($value, $type)
|
||||
{
|
||||
return $this->db->fetchRow(
|
||||
'SELECT
|
||||
hm.id,
|
||||
hm.created_at,
|
||||
hm.wiedervorlage_stage_id,
|
||||
hm.label,
|
||||
hm.value,
|
||||
hm.type FROM hs_mapping_leads `hm` WHERE hm.value=:value AND hm.type=:type',
|
||||
['value' => $value, 'type' => $type]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $dbName
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getAddressFreeFields($dbName)
|
||||
{
|
||||
return $this->db->fetchCol(
|
||||
'
|
||||
SELECT `COLUMN_NAME` FROM `INFORMATION_SCHEMA`.`COLUMNS` WHERE TABLE_SCHEMA=:db AND TABLE_NAME=:table AND
|
||||
COLUMN_NAME LIKE "adressefreifeld%"
|
||||
',
|
||||
[
|
||||
'db' => $dbName,
|
||||
'table' => 'firmendaten',
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getConfiguredFreeAddressFieldValues()
|
||||
{
|
||||
return $this->db->fetchCol(
|
||||
'SELECT f.wert FROM firmendaten_werte `f` WHERE name LIKE "adressetabellezusatz%" AND f.wert !="" AND f.wert IS NOT NULL'
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,192 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\Hubspot;
|
||||
|
||||
use Xentral\Components\Database\Database;
|
||||
use Xentral\Modules\Hubspot\Exception\HubspotException;
|
||||
|
||||
final class HubspotContactPropertyService
|
||||
{
|
||||
|
||||
/** @var HubspotClientService $client */
|
||||
private $client;
|
||||
|
||||
/** @var HubspotContactPropertyGateway $gateway */
|
||||
private $gateway;
|
||||
|
||||
/** @var Database $db */
|
||||
private $db;
|
||||
|
||||
/**
|
||||
* @param HubspotClientService $client
|
||||
* @param HubspotContactPropertyGateway $gateway
|
||||
* @param Database $db
|
||||
*/
|
||||
public function __construct(HubspotClientService $client, HubspotContactPropertyGateway $gateway, Database $db)
|
||||
{
|
||||
$this->client = $client;
|
||||
$this->gateway = $gateway;
|
||||
$this->db = $db;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return HubspotHttpResponseService
|
||||
*/
|
||||
public function getProperties()
|
||||
{
|
||||
return $this->client->setResource('getAllContactProperties')->read();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param string $type
|
||||
*
|
||||
* @throws HubspotException
|
||||
*
|
||||
* @return HubspotHttpResponseService
|
||||
*/
|
||||
public function getProperty(string $name, string $type = 'contact')
|
||||
{
|
||||
if (empty($name)) {
|
||||
throw new HubspotException('Property name is missing');
|
||||
}
|
||||
$resource = 'getContactProperty';
|
||||
if ($type === 'company') {
|
||||
$resource = 'getCompanyProperty';
|
||||
}
|
||||
|
||||
return $this->client->setResource($resource)->read([], [$name]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $type
|
||||
* @param bool $withLabel
|
||||
*
|
||||
* @throws HubspotException
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getHsLeadStatus(string $type = 'contact', bool $withLabel = true)
|
||||
{
|
||||
$response = $this->getProperty('hs_lead_status', $type);
|
||||
if ($response->getStatusCode() !== 200) {
|
||||
throw new HubspotException($response->getError());
|
||||
}
|
||||
|
||||
if (($data = $response->getJson()) && array_key_exists('options', $data)) {
|
||||
if ($withLabel === false) {
|
||||
return array_column($data['options'], 'value');
|
||||
}
|
||||
$response = [];
|
||||
$options = $data['options'];
|
||||
foreach ($options as $option) {
|
||||
$response[$option['value']] = $option['label'];
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
public function getHsLeadRating()
|
||||
{
|
||||
$response = $this->getProperty('lifecyclestage');
|
||||
if ($response->getStatusCode() !== 200) {
|
||||
throw new HubspotException($response->getError());
|
||||
}
|
||||
|
||||
if (($data = $response->getJson()) && array_key_exists('options', $data)) {
|
||||
return array_column($data['options'], 'value');
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $scope
|
||||
*
|
||||
* @throws HubspotException
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getUpdatedLeadStatuses(string $scope): array
|
||||
{
|
||||
$customFreeFieldValue = [];
|
||||
$leadStatus = $this->gateway->getLeadsByType('status', false, $scope);
|
||||
$dbStatuses = array_column($leadStatus, 'value');
|
||||
|
||||
$remoteStatusContact = $this->getHsLeadStatus($scope);
|
||||
$remoteStatusContactKey = array_keys($remoteStatusContact);
|
||||
|
||||
$statusContactGone = array_diff($dbStatuses, $remoteStatusContactKey);
|
||||
if (!empty($statusContactGone)) {
|
||||
foreach ($statusContactGone as $valueGone) {
|
||||
$delGone = "DELETE FROM hs_mapping_leads
|
||||
WHERE value = :value AND type = 'status' AND setting_scope = 'contact'";
|
||||
$this->db->perform($delGone, ['value' => $valueGone]);
|
||||
}
|
||||
}
|
||||
|
||||
$statusContactNew = array_diff($remoteStatusContactKey, $dbStatuses);
|
||||
if (!empty($statusContactNew)) {
|
||||
foreach ($remoteStatusContact as $status => $label) {
|
||||
if (!in_array($status, $statusContactNew, true)) {
|
||||
continue;
|
||||
}
|
||||
$customFreeFieldValue[] = sprintf('%s=>%s', $label, $status);
|
||||
|
||||
$newStatus = 'INSERT INTO hs_mapping_leads (label, value, type, setting_scope)
|
||||
VALUES(:label, :value, "status", :scope)';
|
||||
$this->db->perform(
|
||||
$newStatus,
|
||||
[
|
||||
'label' => $label,
|
||||
'value' => $status,
|
||||
'scope' => $scope,
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $customFreeFieldValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $propertyName
|
||||
* @param string|null $type
|
||||
*
|
||||
* @return array|null
|
||||
*/
|
||||
public function getCustomPropertyByName(string $propertyName, ?string $type = null): ?array
|
||||
{
|
||||
try {
|
||||
$type = $type ?? 'company';
|
||||
$response = $this->getProperty(strtolower($propertyName), $type);
|
||||
} catch (HubspotException $e) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
if (!isset($response)) {
|
||||
try {
|
||||
$response = $this->getProperty(strtolower($propertyName));
|
||||
} catch (HubspotException $e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
if ($response->getStatusCode() !== 200) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$data = $response->getJson();
|
||||
$options = [];
|
||||
$fieldType = $data['fieldType'];
|
||||
$fieldLabel = $data['label'];
|
||||
$name = $data['name'];
|
||||
if (array_key_exists('options', $data)) {
|
||||
$options = !empty($data['options'])? array_column($data['options'], 'value') : [];
|
||||
}
|
||||
return ['fieldName' => $name, 'fieldType' => $fieldType, 'label' => $fieldLabel, 'options' => $options];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,381 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\Hubspot;
|
||||
|
||||
use JsonException;
|
||||
use Xentral\Modules\Hubspot\HubspotHttpResponseService as Response;
|
||||
use Xentral\Modules\Hubspot\Exception\HubspotException;
|
||||
use Xentral\Modules\Hubspot\Validators\ContactValidator;
|
||||
|
||||
|
||||
final class HubspotContactService
|
||||
{
|
||||
|
||||
/** @var int[] $itemsCount */
|
||||
private $itemsCount = ['count' => 100];
|
||||
|
||||
/** @var string[] $allowedSyncContactOptions */
|
||||
private $allowedSyncContactOptions = [
|
||||
'recently_created' => 'getRecentlyCreatedContacts',
|
||||
'recently_updated' => 'getRecentlyUpdatedContacts',
|
||||
'all' => 'getContacts',
|
||||
'companies' => 'getCompanies',
|
||||
'recent_companies' => 'getRecentCompanies',
|
||||
];
|
||||
|
||||
/** @var HubspotClientService $client */
|
||||
private $client;
|
||||
|
||||
/** @var HubspotMetaService $meta */
|
||||
private $meta;
|
||||
|
||||
/** @var ContactValidator $validator */
|
||||
private $validator;
|
||||
|
||||
/** @var HubspotConfigurationService $configurationService */
|
||||
private $configurationService;
|
||||
|
||||
/**
|
||||
* @param HubspotClientService $client
|
||||
* @param HubspotMetaService $meta
|
||||
* @param ContactValidator $validator
|
||||
* @param HubspotConfigurationService $configurationService
|
||||
*/
|
||||
public function __construct(
|
||||
HubspotClientService $client,
|
||||
HubspotMetaService $meta,
|
||||
ContactValidator $validator,
|
||||
HubspotConfigurationService $configurationService
|
||||
) {
|
||||
$this->client = $client;
|
||||
$this->meta = $meta;
|
||||
$this->validator = $validator;
|
||||
$this->configurationService = $configurationService;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $options
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function getContacts($options = []): Response
|
||||
{
|
||||
return $this->client->setResource('allContacts')->read($options);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $options
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function getRecentlyUpdatedContacts($options = []): Response
|
||||
{
|
||||
$options += $this->itemsCount;
|
||||
|
||||
return $this->client->setResource('recentlyUpdatedContacts')->read($options);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $contactId
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function deleteContact($contactId = 0): Response
|
||||
{
|
||||
return $this->client->setResource('deleteContact')->delete([], [$contactId]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @throws HubspotException
|
||||
*
|
||||
* @return HubspotHttpResponseService
|
||||
*/
|
||||
public function createContact($data = []): Response
|
||||
{
|
||||
if (!$this->validator->isValid($data)) {
|
||||
throw new HubSpotException(sprintf('Invalid contact data'));
|
||||
}
|
||||
|
||||
$contactData = $this->validator->getData();
|
||||
|
||||
if (array_key_exists('salutation', $data) && $data['salutation'] === 'firma') {
|
||||
$contactData['name'] = $data['lastname'];
|
||||
$identity = $this->formatCompanyIdentity($contactData);
|
||||
return $this->client->setResource('createCompany')->post($identity);
|
||||
}
|
||||
|
||||
$identity = $this->formatContactIdentity($contactData);
|
||||
|
||||
return $this->client->setResource('createContact')->post($identity);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $contactId
|
||||
* @param array $data
|
||||
*
|
||||
* @throws HubspotException
|
||||
*
|
||||
* @return HubspotHttpResponseService
|
||||
*/
|
||||
public function updateContactById($contactId, $data = []): Response
|
||||
{
|
||||
if (!$this->validator->isValid($data)) {
|
||||
throw new HubspotException(sprintf('Invalid contact data'));
|
||||
}
|
||||
|
||||
$contactData = $this->validator->getData();
|
||||
if (array_key_exists('salutation', $data) && $data['salutation'] === 'firma') {
|
||||
$contactData['name'] = $data['lastname'];
|
||||
$identity = $this->formatCompanyIdentity($contactData);
|
||||
return $this->client->setResource('updateCompany')->put($identity, [$contactId]);
|
||||
}
|
||||
|
||||
$identity = $this->formatContactIdentity($contactData);
|
||||
|
||||
return $this->client->setResource('updateContact')->post($identity, [$contactId]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
private function formatContactIdentity($data)
|
||||
{
|
||||
$identity['properties'] = [];
|
||||
foreach ($data as $property => $value) {
|
||||
$identity['properties'][] = [
|
||||
'property' => $property,
|
||||
'value' => $value,
|
||||
];
|
||||
}
|
||||
|
||||
return $identity;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function formatCompanyIdentity(array $data) : array
|
||||
{
|
||||
$whiteList = ['name',
|
||||
'phone',
|
||||
'hs_lead_status',
|
||||
'website',
|
||||
'domain',
|
||||
'lifecyclestage',
|
||||
'zip',
|
||||
'city',
|
||||
'country',
|
||||
'state',
|
||||
'address',
|
||||
'numberofemployees',
|
||||
'description'
|
||||
];
|
||||
|
||||
$settings = $this->configurationService->getSettings();
|
||||
$defaultCustomFields = array_key_exists('hubspot_address_free_fields', $settings) ?
|
||||
$settings['hubspot_address_free_fields'] : [];
|
||||
if (!empty($defaultCustomFields)) {
|
||||
foreach ($defaultCustomFields as $defaultCustomField => $systemField) {
|
||||
$whiteList[] = "xthubspot_{$defaultCustomField}";
|
||||
}
|
||||
}
|
||||
|
||||
$identity['properties'] = [];
|
||||
foreach ($data as $property => $value) {
|
||||
if (!in_array($property, $whiteList, true)) {
|
||||
continue;
|
||||
}
|
||||
if (strpos($property, 'xthubspot_') !== false) {
|
||||
$property = str_replace('xthubspot_', '', $property);
|
||||
}
|
||||
$identity['properties'][] = [
|
||||
'name' => $property,
|
||||
'value' => $value,
|
||||
];
|
||||
}
|
||||
|
||||
return $identity;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $options
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function getRecentlyCreatedContacts($options = [])
|
||||
{
|
||||
$options += $this->itemsCount;
|
||||
|
||||
return $this->client->setResource('recentlyAddedContacts')->read($options);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $type
|
||||
* @param array $options
|
||||
*
|
||||
* @throws Exception\MetaException
|
||||
* @throws HubspotException
|
||||
* @throws JsonException
|
||||
*
|
||||
* @return HubspotHttpResponseService
|
||||
*/
|
||||
public function pullContacts($type = 'all', $options = []): Response
|
||||
{
|
||||
$options += $this->itemsCount;
|
||||
if ('all' !== $type && !in_array($type, array_keys($this->allowedSyncContactOptions), true)) {
|
||||
throw new HubSpotException(sprintf('Sync Type %s not allowed', $type));
|
||||
}
|
||||
|
||||
if ($type !== 'all') {
|
||||
$metaInfo = $this->meta->setName($type)->get();
|
||||
if (!empty($metaInfo)) {
|
||||
$options = array_merge(
|
||||
$options,
|
||||
[
|
||||
'vidOffset' => $metaInfo['vidOffset'],
|
||||
'timeOffset' => $metaInfo['timeOffset'],
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/** @var Response $response */
|
||||
return $this->{$this->allowedSyncContactOptions[$type]}($options);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $contactId
|
||||
*
|
||||
* @return HubspotHttpResponseService
|
||||
*/
|
||||
public function getContactById($contactId): Response
|
||||
{
|
||||
return $this->client->setResource('getContactById')->read([], [$contactId]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return HubspotHttpResponseService
|
||||
*/
|
||||
public function getCompanies(): HubspotHttpResponseService
|
||||
{
|
||||
return $this->client->setResource('getCompanies')->read();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return HubspotHttpResponseService
|
||||
*/
|
||||
public function getRecentCompanies(): HubspotHttpResponseService
|
||||
{
|
||||
return $this->client->setResource('getRecentCompanies')->read();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $companyId
|
||||
*
|
||||
* @return HubspotHttpResponseService
|
||||
*/
|
||||
public function getCompanyById(int $companyId): HubspotHttpResponseService
|
||||
{
|
||||
return $this->client->setResource('getCompanyById')->read([], [$companyId]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $type
|
||||
* @param array $options
|
||||
*
|
||||
* @throws Exception\MetaException
|
||||
* @throws HubspotException
|
||||
* @throws JsonException
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function pullCompanies($type = 'all', $options = [])
|
||||
{
|
||||
$options += $this->itemsCount;
|
||||
|
||||
if (in_array($type, ['all', 'company'])) {
|
||||
$type = 'companies';
|
||||
}
|
||||
|
||||
if (!in_array($type, array_keys($this->allowedSyncContactOptions), true)) {
|
||||
throw new HubSpotException(sprintf('Sync Type %s not allowed', $type));
|
||||
}
|
||||
|
||||
if (($type !== 'companies') && $metaInfo = $this->meta->setName($type)->get()) {
|
||||
$options = array_merge(
|
||||
$options,
|
||||
[
|
||||
'vidOffset' => $metaInfo['vidOffset'],
|
||||
'timeOffset' => $metaInfo['timeOffset'],
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/** @var Response $response */
|
||||
return $this->{$this->allowedSyncContactOptions[$type]}($options);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $companyId
|
||||
*
|
||||
* @return HubspotHttpResponseService
|
||||
*/
|
||||
public function getCompanyContacts(int $companyId): HubspotHttpResponseService
|
||||
{
|
||||
return $this->client->setResource('getCompanyContacts')->read([], [$companyId]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $companyId
|
||||
* @param int $contactId
|
||||
*
|
||||
* @return HubspotHttpResponseService
|
||||
*/
|
||||
public function addContactToCompany(int $companyId, int $contactId): HubspotHttpResponseService
|
||||
{
|
||||
$data = [
|
||||
"fromObjectId" => $contactId,
|
||||
"toObjectId" => $companyId,
|
||||
"category" => 'HUBSPOT_DEFINED',
|
||||
"definitionId" => 1,
|
||||
];
|
||||
|
||||
return $this->client->setResource('getCompanyContacts')->put($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $companyId
|
||||
* @param int $contactId
|
||||
*
|
||||
* @return HubspotHttpResponseService
|
||||
*/
|
||||
public function removeContactFromCompany(int $companyId, int $contactId): HubspotHttpResponseService
|
||||
{
|
||||
$data = [
|
||||
"fromObjectId" => $contactId,
|
||||
"toObjectId" => $companyId,
|
||||
"category" => 'HUBSPOT_DEFINED',
|
||||
"definitionId" => 1,
|
||||
];
|
||||
|
||||
return $this->client->setResource('deleteContactFromCompany')->put($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $ownerId
|
||||
*
|
||||
* @throws HubspotException
|
||||
*
|
||||
* @return HubspotHttpResponseService
|
||||
*/
|
||||
public function getHubspotOwner(int $ownerId): HubspotHttpResponseService
|
||||
{
|
||||
return $this->client->apiCall('getHubspotOwner', 'get', [], [$ownerId]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\Hubspot;
|
||||
|
||||
use Xentral\Components\Database\Database;
|
||||
use Xentral\Modules\Hubspot\Exception\HubspotDealGatewayNotFoundException;
|
||||
|
||||
final class HubspotDealGateway
|
||||
{
|
||||
/** @var Database $db */
|
||||
private $db;
|
||||
|
||||
/**
|
||||
* @param Database $db
|
||||
*/
|
||||
public function __construct(Database $db)
|
||||
{
|
||||
$this->db = $db;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $hsDealId
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getByHubspotId($hsDealId)
|
||||
{
|
||||
if (!is_numeric($hsDealId)) {
|
||||
throw new HubspotDealGatewayNotFoundException(
|
||||
sprintf(
|
||||
'Hubspot Deal not found: HubspotID%s',
|
||||
$hsDealId
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return $this->db->fetchRow(
|
||||
'SELECT
|
||||
d.id,
|
||||
d.created_at,
|
||||
d.data,
|
||||
d.wiedervorlage_id
|
||||
FROM `hubspot_deals` AS `d` WHERE d.hidden = 0 AND d.hs_deal_id = :id',
|
||||
['id' => (int)$hsDealId]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $resubmissionId
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getByResubmissionId($resubmissionId)
|
||||
{
|
||||
if (!is_numeric($resubmissionId)) {
|
||||
throw new HubspotDealGatewayNotFoundException(
|
||||
sprintf(
|
||||
'Hubspot Deal not found for : ResubmissionId%s',
|
||||
$resubmissionId
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return $this->db->fetchRow(
|
||||
'SELECT
|
||||
d.id,
|
||||
d.created_at,
|
||||
d.data,
|
||||
d.wiedervorlage_id,
|
||||
d.hs_deal_id
|
||||
FROM `hubspot_deals` AS `d` WHERE d.hidden = 0 AND d.wiedervorlage_id = :id',
|
||||
['id' => (int)$resubmissionId]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $stageId
|
||||
**
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getMappingStageByResubmissionStageId($stageId)
|
||||
{
|
||||
if (!is_numeric($stageId)) {
|
||||
throw new HubspotDealGatewayNotFoundException(
|
||||
sprintf(
|
||||
'Hubspot Deal Mapping not found for stage: ID%s',
|
||||
$stageId
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return $this->db->fetchRow(
|
||||
'SELECT
|
||||
hm.id,
|
||||
hm.created_at,
|
||||
hm.wiedervorlage_stage_id,
|
||||
hm.label,
|
||||
hm.value,
|
||||
hm.wiedervorlage_view_id,
|
||||
hm.type FROM hs_mapping_leads `hm` WHERE hm.wiedervorlage_stage_id=:resubmission_id AND hm.type=:type',
|
||||
['resubmission_id' => $stageId, 'type' => 'deals']
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $value
|
||||
**
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getMappingStageByValue($value)
|
||||
{
|
||||
if (!is_string($value)) {
|
||||
throw new HubspotDealGatewayNotFoundException(
|
||||
sprintf(
|
||||
'Hubspot Deal Mapping not found for value: %s',
|
||||
$value
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return $this->db->fetchRow(
|
||||
'SELECT
|
||||
hm.id,
|
||||
hm.created_at,
|
||||
hm.wiedervorlage_stage_id,
|
||||
hm.label,
|
||||
hm.value,
|
||||
hm.wiedervorlage_view_id,
|
||||
hm.type FROM hs_mapping_leads `hm` WHERE hm.value=:value AND hm.type=:type',
|
||||
['value' => $value, 'type' => 'deals']
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,172 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\Hubspot;
|
||||
|
||||
use Xentral\Components\Database\Database;
|
||||
use Xentral\Modules\Hubspot\Exception\HubspotException;
|
||||
|
||||
final class HubspotDealPropertyService
|
||||
{
|
||||
|
||||
/**
|
||||
* @var HubspotClientService
|
||||
*/
|
||||
private $client;
|
||||
/**
|
||||
* @var Database
|
||||
*/
|
||||
private $db;
|
||||
|
||||
/** @var HubspotContactPropertyGateway $propertyGateway */
|
||||
private $propertyGateway;
|
||||
|
||||
/**
|
||||
* HubspotDealPropertyService constructor.
|
||||
*
|
||||
* @param HubspotClientService $client
|
||||
* @param Database $db
|
||||
* @param HubspotContactPropertyGateway $propertyGateway
|
||||
*/
|
||||
public function __construct(
|
||||
HubspotClientService $client,
|
||||
Database $db,
|
||||
HubspotContactPropertyGateway $propertyGateway
|
||||
) {
|
||||
$this->client = $client;
|
||||
$this->db = $db;
|
||||
$this->propertyGateway = $propertyGateway;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws HubspotException
|
||||
* @return array
|
||||
*/
|
||||
public function getDealStages()
|
||||
{
|
||||
$response = $this->client->setResource('getPipelineProperties')->read([], ['deals']);
|
||||
if ($response->getStatusCode() !== 200) {
|
||||
throw new HubspotException($response->getError());
|
||||
}
|
||||
|
||||
if (($data = $response->getJson()) && array_key_exists('results', $data)) {
|
||||
$stages = array_column($data['results'], 'stages');
|
||||
|
||||
return reset($stages);
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
public function installDealStages()
|
||||
{
|
||||
// Get Deal Stages
|
||||
$firstStage = 0;
|
||||
$viewId = 0;
|
||||
if ($dealStages = $this->propertyGateway->getLeadsByType('deals')) {
|
||||
$stage = array_unique(array_column($dealStages, 'wiedervorlage_stage_id'));
|
||||
$firstStage = $stage[0];
|
||||
}
|
||||
if ($firstStage > 0) {
|
||||
$viewId = $this->db->fetchValue(
|
||||
'SELECT ws.view FROM wiedervorlage_stages `ws` WHERE ws.id=:id',
|
||||
[
|
||||
'id' => $firstStage,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
if (empty($firstStage) || empty($viewId)) {
|
||||
// CHECK the default view
|
||||
if ($this->db->fetchValue(
|
||||
'SELECT wv.id FROM wiedervorlage_view `wv`
|
||||
WHERE wv.name=:name AND wv.shortname=:desc AND wv.active=:active AND wv.project=0',
|
||||
[
|
||||
'name' => 'Hubspot',
|
||||
'desc' => 'Hubspot',
|
||||
'active' => 1,
|
||||
]
|
||||
)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->db->perform(
|
||||
'INSERT INTO wiedervorlage_view(name,shortname,active) VALUES (:name,:desc_short,1)',
|
||||
[
|
||||
'name' => 'Hubspot',
|
||||
'desc_short' => 'Hubspot',
|
||||
]
|
||||
);
|
||||
$viewId = $this->db->lastInsertId();
|
||||
}
|
||||
|
||||
if ($viewId > 0 && ($ahDealStages = $this->getDealStages())) {
|
||||
$position = (int)$this->getMaxSortByViewId($viewId) + 1;
|
||||
foreach ($ahDealStages as $hDealStage) {
|
||||
if ($this->db->fetchValue(
|
||||
'SELECT hm.id FROM hs_mapping_leads `hm` WHERE hm.value=:value AND hm.type=:type',
|
||||
[
|
||||
'value' => $hDealStage['stageId'],
|
||||
'type' => 'deals',
|
||||
]
|
||||
)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->db->perform(
|
||||
'INSERT INTO wiedervorlage_stages (kurzbezeichnung,name,stageausblenden,sort,view)
|
||||
VALUES(:desc, :name,:enabled, :position,:wiedervorlage_view_id)',
|
||||
[
|
||||
'desc' => $hDealStage['label'],
|
||||
'name' => $hDealStage['label'],
|
||||
'position' => $position,
|
||||
'wiedervorlage_view_id' => $viewId,
|
||||
'enabled' => 1,
|
||||
]
|
||||
);
|
||||
|
||||
if ($stageId = $this->db->lastInsertId()) {
|
||||
$this->db->perform(
|
||||
'INSERT INTO hs_mapping_leads (`label`, `value`, `type`, `wiedervorlage_stage_id`, `is_system`,
|
||||
`wiedervorlage_view_id`)
|
||||
VALUES(:label, :value,:type, :wstage_id, :is_system, :view_id)',
|
||||
[
|
||||
'label' => $hDealStage['label'],
|
||||
'value' => $hDealStage['stageId'],
|
||||
'type' => 'deals',
|
||||
'wstage_id' => $stageId,
|
||||
'is_system' => 1,
|
||||
'view_id' => $viewId,
|
||||
]
|
||||
);
|
||||
}
|
||||
$position++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $viewId
|
||||
*
|
||||
* @return false|float|int|string
|
||||
*/
|
||||
public function getMaxSortByViewId($viewId)
|
||||
{
|
||||
return $this->db->fetchValue(
|
||||
'SELECT MAX(ws.sort) FROM wiedervorlage_stages `ws` WHERE ws.`view`=:id',
|
||||
['id' => $viewId]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $viewId
|
||||
*
|
||||
* @return false|float|int|string
|
||||
*/
|
||||
public function getMinStageByViewId($viewId)
|
||||
{
|
||||
return $this->db->fetchValue(
|
||||
'SELECT MIN(ws.id) FROM wiedervorlage_stages `ws` WHERE ws.`view`=:id',
|
||||
['id' => $viewId]
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,174 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\Hubspot;
|
||||
|
||||
use Xentral\Modules\Hubspot\Exception\HubspotException;
|
||||
use Xentral\Modules\Hubspot\HubspotHttpResponseService as Response;
|
||||
use Xentral\Modules\Hubspot\Validators\DealValidator;
|
||||
|
||||
final class HubspotDealService
|
||||
{
|
||||
/** @var array $allowedSyncDealsOptions */
|
||||
private $allowedSyncDealsOptions = [
|
||||
'recently_created_deals' => 'getRecentlyCreatedDeals',
|
||||
'recently_updated_deals' => 'getRecentlyUpdatedDeals',
|
||||
'all_deals' => 'getDeals',
|
||||
];
|
||||
|
||||
/** @var array $asDealPhases */
|
||||
private $asDealPhases = [
|
||||
'appointmentscheduled',
|
||||
'qualifiedtobuy',
|
||||
'presentationscheduled',
|
||||
'decisionmakerboughtin',
|
||||
'contractsent',
|
||||
'closedwon',
|
||||
'closedlost',
|
||||
];
|
||||
|
||||
private $limit = ['limit' => 200];
|
||||
|
||||
/** @var HubspotClientService $client */
|
||||
private $client;
|
||||
|
||||
/** @var HubspotMetaService $meta */
|
||||
private $meta;
|
||||
|
||||
/** @var DealValidator $validator */
|
||||
private $validator;
|
||||
|
||||
public function __construct(
|
||||
HubspotClientService $client,
|
||||
HubspotMetaService $meta,
|
||||
DealValidator $validator
|
||||
) {
|
||||
$this->client = $client;
|
||||
$this->meta = $meta;
|
||||
$this->validator = $validator;
|
||||
}
|
||||
|
||||
public function createDeal($data = [])
|
||||
{
|
||||
if (!$this->validator->isValid($data)) {
|
||||
throw new HubSpotException(sprintf('Invalid Deal data'));
|
||||
}
|
||||
$default = ['pipeline' => 'default', 'dealstage' => 'appointmentscheduled'];
|
||||
$data += $default;
|
||||
|
||||
if (!$this->validator->isValid($data)) {
|
||||
throw new HubSpotException(sprintf('Invalid Deal data'));
|
||||
}
|
||||
|
||||
$deal = $this->formatDealData($this->validator->getData());
|
||||
|
||||
return $this->client->setResource('createDeal')->post($deal);
|
||||
}
|
||||
|
||||
public function getDealById($dealId)
|
||||
{
|
||||
return $this->client->setResource('getDealById')->read([], [$dealId]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $options
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function getDeals($options = [])
|
||||
{
|
||||
$options += $this->limit;
|
||||
|
||||
return $this->client->setResource('allDeals')->read($options);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $options
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function getRecentlyUpdatedDeals($options = [])
|
||||
{
|
||||
$options += $this->limit;
|
||||
|
||||
return $this->client->setResource('recentlyUpdatedDeals')->read($options);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $dealId
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function deleteDeal($dealId)
|
||||
{
|
||||
return $this->client->setResource('deleteDeal')->delete([], [$dealId]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $dealId
|
||||
* @param array $data
|
||||
*
|
||||
* @return HubspotHttpResponseService
|
||||
*/
|
||||
public function updateDealById($dealId, $data = [])
|
||||
{
|
||||
if (!$this->validator->isValid($data)) {
|
||||
throw new HubSpotException(sprintf('Invalid Deal data'));
|
||||
}
|
||||
|
||||
$deal = $this->formatDealData($this->validator->getData());
|
||||
|
||||
return $this->client->setResource('updateDeal')->put($deal, [$dealId]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param array $options
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function getRecentlyCreatedDeals($options = [])
|
||||
{
|
||||
$options += $this->limit;
|
||||
|
||||
return $this->client->setResource('recentlyAddedDeals')->read($options);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $type
|
||||
* @param array $options
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function pullDeals($type = 'all', $options = [])
|
||||
{
|
||||
if ('all' !== $type && !in_array($type, array_keys($this->allowedSyncDealsOptions), true)) {
|
||||
throw new HubSpotException(sprintf('Sync Deal with Type %s not allowed', $type));
|
||||
}
|
||||
|
||||
if (($type !== 'all') && ($metaInfo = $this->meta->setName($type)->get())) {
|
||||
$since = !array_key_exists('since', $metaInfo) ? time() * 1000 : $metaInfo['since'];
|
||||
$options += ['offset' => $metaInfo['offset'], 'since' => $since];
|
||||
}
|
||||
|
||||
/** @var Response $response */
|
||||
return $this->{$this->allowedSyncDealsOptions[$type]}($options);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
private function formatDealData($data)
|
||||
{
|
||||
$identity['properties'] = [];
|
||||
foreach ($data as $property => $value) {
|
||||
$identity['properties'][] = [
|
||||
'name' => $property,
|
||||
'value' => $value,
|
||||
];
|
||||
}
|
||||
|
||||
return $identity;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,177 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\Hubspot;
|
||||
|
||||
use Xentral\Modules\Hubspot\Exception\HubspotEngagementException;
|
||||
|
||||
final class HubspotEngagementService
|
||||
{
|
||||
|
||||
/** @var HubspotClientService $client */
|
||||
private $client;
|
||||
|
||||
/** @var string[] */
|
||||
private const ASSOCIATIONS_VALIDATOR = [
|
||||
'contact' => 'contactIds',
|
||||
'company' => 'companyIds',
|
||||
'deal' => 'dealIds',
|
||||
'owner' => 'ownerIds',
|
||||
'ticket' => 'ticketIds',
|
||||
];
|
||||
|
||||
/** @var string[] */
|
||||
private const ALLOWED_TYPES = ['EMAIL', 'CALL', 'MEETING', 'TASK', 'NOTE'];
|
||||
|
||||
/**
|
||||
* @param HubspotClientService $client
|
||||
*/
|
||||
public function __construct(HubspotClientService $client)
|
||||
{
|
||||
$this->client = $client;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $body
|
||||
* @param array $associationIds
|
||||
* @param string $type
|
||||
*
|
||||
* @return HubspotHttpResponseService|null
|
||||
*/
|
||||
public function createCompanyEngagement(
|
||||
string $body,
|
||||
array $associationIds = [],
|
||||
string $type = 'NOTE'
|
||||
): ?HubspotHttpResponseService {
|
||||
try {
|
||||
$data = $this->getCreateData($type, $body, 'company', $associationIds);
|
||||
$response = $this->client->apiCall('createEngagement', 'post', $data);
|
||||
} catch (Exception\HubspotException | HubspotEngagementException $e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $body
|
||||
* @param array $associationIds
|
||||
* @param string $type
|
||||
*
|
||||
* @return HubspotHttpResponseService|null
|
||||
*/
|
||||
public function createContactEngagement(
|
||||
string $body,
|
||||
array $associationIds = [],
|
||||
string $type = 'NOTE'
|
||||
): ?HubspotHttpResponseService {
|
||||
try {
|
||||
$data = $this->getCreateData($type, $body, 'contact', $associationIds);
|
||||
$response = $this->client->apiCall('createEngagement', 'post', $data);
|
||||
} catch (Exception\HubspotException | HubspotEngagementException $e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $body
|
||||
* @param array $associationIds
|
||||
* @param string $type
|
||||
*
|
||||
* @return HubspotHttpResponseService|null
|
||||
*/
|
||||
public function createDealEngagement(
|
||||
string $body,
|
||||
array $associationIds = [],
|
||||
string $type = 'NOTE'
|
||||
): ?HubspotHttpResponseService {
|
||||
try {
|
||||
$data = $this->getCreateData($type, $body, 'deal', $associationIds);
|
||||
$response = $this->client->apiCall('createEngagement', 'post', $data);
|
||||
} catch (Exception\HubspotException | HubspotEngagementException $e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $engagementId
|
||||
* @param string $body
|
||||
* @param string $intendedTo
|
||||
* @param string $type
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function updateEngagement(int $engagementId, string $body, string $intendedTo, string $type = 'NOTE'): bool
|
||||
{
|
||||
try {
|
||||
$data = $this->getCreateData($type, $body, $intendedTo);
|
||||
$response = $this->client->apiCall('updateEngagement', 'patch', $data, [$engagementId]);
|
||||
} catch (Exception\HubspotException | HubspotEngagementException $e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $response->getStatusCode() === 200;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $options
|
||||
*
|
||||
* @throws Exception\HubspotException
|
||||
*
|
||||
* @return HubspotHttpResponseService
|
||||
*/
|
||||
public function getRecentEngagements(array $options = []): HubspotHttpResponseService
|
||||
{
|
||||
if (array_key_exists('offset', $options) && array_key_exists('since', $options)) {
|
||||
unset($options['since'], $options['offset']);
|
||||
}
|
||||
|
||||
return $this->client->apiCall('getRecentEngagements', 'get', $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $type
|
||||
* @param string $body
|
||||
* @param string $intendedTo
|
||||
* @param array $associationIds
|
||||
*
|
||||
* @throws HubspotEngagementException
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function getCreateData(string $type, string $body, string $intendedTo, array $associationIds = []): array
|
||||
{
|
||||
if (!in_array($type, self::ALLOWED_TYPES)) {
|
||||
throw new HubspotEngagementException(sprintf('Type %s is not allowed !', $type));
|
||||
}
|
||||
|
||||
if (!array_key_exists($intendedTo, self::ASSOCIATIONS_VALIDATOR)) {
|
||||
throw new HubspotEngagementException(sprintf('Intended Association %s is not allowed !', $intendedTo));
|
||||
}
|
||||
|
||||
$data = [
|
||||
'engagement' => [
|
||||
'active' => true,
|
||||
'type' => $type,
|
||||
'timestamp' => time() * 1000,
|
||||
],
|
||||
];
|
||||
|
||||
if (!empty($body)) {
|
||||
$data['metadata'] = ['body' => $body];
|
||||
}
|
||||
|
||||
if (!empty($associationIds)) {
|
||||
$data['associations'] = [
|
||||
self::ASSOCIATIONS_VALIDATOR[$intendedTo] => $associationIds,
|
||||
];
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\Hubspot;
|
||||
|
||||
use Xentral\Components\Database\Database;
|
||||
use Xentral\Components\Database\Exception\DatabaseExceptionInterface;
|
||||
use Xentral\Modules\Hubspot\Exception\HubspotException;
|
||||
|
||||
final class HubspotEventService
|
||||
{
|
||||
|
||||
/** @var Database $db */
|
||||
private $db;
|
||||
|
||||
public function __construct(Database $db)
|
||||
{
|
||||
$this->db = $db;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $event
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function add(string $event): int
|
||||
{
|
||||
$add = 'INSERT INTO `hubspot_events` (`event`, `created_at` )
|
||||
VALUES (:event, NOW())';
|
||||
try {
|
||||
$this->db->perform($add, ['event' => $event]);
|
||||
} catch (DatabaseExceptionInterface $exception) {
|
||||
throw new HubspotException($exception->getMessage());
|
||||
}
|
||||
|
||||
return $this->db->lastInsertId();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $id
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function deleteById(int $id): void
|
||||
{
|
||||
$this->db->perform('DELETE FROM `hubspot_events` WHERE id = :id', ['id' => $id]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function deleteAll(): void
|
||||
{
|
||||
$this->db->perform('DELETE FROM `hubspot_events`');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $days
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function deleteByInterval(int $days = 30): void
|
||||
{
|
||||
$sql = 'DELETE FROM `hubspot_events` WHERE `created_at` < DATE_SUB(NOW(), INTERVAL :days DAY)';
|
||||
$this->db->perform($sql, ['days' => $days]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,198 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\Hubspot;
|
||||
|
||||
use GuzzleHttp\Exception\GuzzleException;
|
||||
use GuzzleHttp\Exception\RequestException;
|
||||
use GuzzleHttp\Client;
|
||||
use Xentral\Modules\Hubspot\HubspotHttpResponseService as Response;
|
||||
use Xentral\Modules\Hubspot\Exception\HttpClientException;
|
||||
use Xentral\Modules\Hubspot\Interfaces\HubspotHttpClientInterface;
|
||||
|
||||
final class HubspotHttpClientService implements HubspotHttpClientInterface
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $endpoint = null;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $userAgent = [];
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $hRequestVerbs = [
|
||||
self::GET_REQUEST => null,
|
||||
self::POST_REQUEST => 'json',
|
||||
self::PUT_REQUEST => 'json',
|
||||
self::PATCH_REQUEST => 'json',
|
||||
self::DELETE_REQUEST => null,
|
||||
];
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $timeout;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $_headers = [];
|
||||
|
||||
/**
|
||||
* @param int $timeout > 0
|
||||
*
|
||||
*/
|
||||
public function __construct($timeout = 0)
|
||||
{
|
||||
if (!is_int($timeout) || $timeout < 0) {
|
||||
throw new HttpClientException(
|
||||
sprintf(
|
||||
'Connection timeout must be an int >= 0, got "%s".',
|
||||
is_object($timeout) ? get_class($timeout) : gettype($timeout) . ' ' . var_export($timeout, true)
|
||||
)
|
||||
);
|
||||
}
|
||||
if (!empty($timeout)) {
|
||||
$this->timeout = $timeout;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $url
|
||||
* @param string $method
|
||||
* @param array $data
|
||||
*
|
||||
* @param array $headers
|
||||
*
|
||||
* @return HubspotHttpResponseService
|
||||
* @throws HttpClientException
|
||||
*/
|
||||
public function performRequest($url, $method, array $data = [], $headers = [])
|
||||
{
|
||||
$this->setHeader($headers);
|
||||
|
||||
$hHeaders = $this->getHeaders();
|
||||
|
||||
try {
|
||||
$client = $this->getClient();
|
||||
|
||||
$keyParam = $this->hRequestVerbs[$method];
|
||||
$paramData = ['headers' => $hHeaders];
|
||||
if ($keyParam !== null) {
|
||||
$paramData[$keyParam] = $data;
|
||||
}
|
||||
|
||||
/** @var Response */
|
||||
$response = $client->request($method, $url, $paramData);
|
||||
|
||||
return new HubspotHttpResponseService($response);
|
||||
} catch (RequestException $exception) {
|
||||
throw new HttpClientException($exception->getMessage());
|
||||
} catch (GuzzleException $exception) {
|
||||
throw new HttpClientException($exception->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Client
|
||||
*/
|
||||
protected function getClient()
|
||||
{
|
||||
return new Client(['timeout' => $this->timeout]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $url
|
||||
* @param array $data
|
||||
* @param array $header
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function get($url, $data = [], $header = [])
|
||||
{
|
||||
if (!empty($data)) {
|
||||
$query = parse_url($url, PHP_URL_QUERY);
|
||||
$newQuery = http_build_query($data);
|
||||
$url = $query ? $url . '&' . $newQuery : $url . '?' . $newQuery;
|
||||
}
|
||||
|
||||
return $this->performRequest($url, static::GET_REQUEST, [], $header);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $url
|
||||
* @param array $data
|
||||
* @param array $header
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function post($url, $data = [], $header = [])
|
||||
{
|
||||
$defHeader = ['Content-Type' => 'application/json', 'Accept' => 'application/json'];
|
||||
$header += $defHeader;
|
||||
|
||||
return $this->performRequest($url, static::POST_REQUEST, $data, $header);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $url
|
||||
* @param array $data
|
||||
* @param array $header
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function patch($url, $data = [], $header = [])
|
||||
{
|
||||
return $this->performRequest($url, static::PATCH_REQUEST, $data, $header);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $url
|
||||
* @param array $data
|
||||
* @param array $header
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function delete($url, $data = [], $header = [])
|
||||
{
|
||||
return $this->performRequest($url, static::DELETE_REQUEST, $data, $header);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $option
|
||||
*/
|
||||
protected function setHeader($option = [])
|
||||
{
|
||||
$this->_headers += $option;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
protected function getHeaders()
|
||||
{
|
||||
$default = ['User-Agent' => 'Xentral-ERP-CRM'];
|
||||
|
||||
return $this->_headers += $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $url
|
||||
* @param array $data
|
||||
* @param array $header
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
public function put($url, $data = [], $header = [])
|
||||
{
|
||||
$defHeader = ['Content-Type' => 'application/json', 'Accept' => 'application/json'];
|
||||
$header += $defHeader;
|
||||
|
||||
return $this->performRequest($url, static::PUT_REQUEST, $data, $header);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\Hubspot;
|
||||
|
||||
use \Psr\Http\Message\ResponseInterface;
|
||||
|
||||
final class HubspotHttpResponseService
|
||||
{
|
||||
|
||||
/** @var ResponseInterface $response */
|
||||
private $response;
|
||||
|
||||
/**
|
||||
* @param ResponseInterface $response
|
||||
*/
|
||||
public function __construct(ResponseInterface $response)
|
||||
{
|
||||
$this->response = $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the json response body
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getJson(): array
|
||||
{
|
||||
$content = (string)$this->response->getBody();
|
||||
$jsonResponse = json_decode($content, true);
|
||||
|
||||
if ($jsonResponse === null || (json_last_error() !== JSON_ERROR_NONE)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return $jsonResponse;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getStatusCode() : int
|
||||
{
|
||||
return $this->response->getStatusCode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the error message
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getError(): string
|
||||
{
|
||||
if (!in_array($this->getStatusCode(), [200, 201, 204])) {
|
||||
if (($resp = $this->getJson()) && array_key_exists('error', $resp)) {
|
||||
return $resp['error'];
|
||||
}
|
||||
|
||||
return 'Unknown Error';
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\Hubspot;
|
||||
|
||||
use Xentral\Modules\Hubspot\Exception\MetaException;
|
||||
|
||||
class HubspotMetaService
|
||||
{
|
||||
|
||||
private $name;
|
||||
private $content;
|
||||
private $extension;
|
||||
private $tmpDir;
|
||||
|
||||
/**
|
||||
* @param string $tmpDir
|
||||
* @param string $ext
|
||||
*/
|
||||
public function __construct(string $tmpDir, $ext = 'json')
|
||||
{
|
||||
$this->extension = $ext;
|
||||
$this->tmpDir = $tmpDir;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
*
|
||||
* @throws MetaException
|
||||
* @return HubspotMetaService
|
||||
*/
|
||||
public function setName(string $name): HubspotMetaService
|
||||
{
|
||||
if (empty($name)) {
|
||||
throw new MetaException('Name cannot be empty');
|
||||
}
|
||||
$this->name = preg_replace('/[^a-zA-Z]+/', '', $name);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws MetaException
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function getFullFileName(): string
|
||||
{
|
||||
$metaTmpDir = $this->tmpDir . 'meta';
|
||||
if (!is_dir($metaTmpDir) && !mkdir($metaTmpDir, 0777, true) && !is_dir($metaTmpDir)) {
|
||||
throw new MetaException(sprintf('Directory "%s" was not created', $metaTmpDir));
|
||||
}
|
||||
|
||||
$metaTmpDir .= DIRECTORY_SEPARATOR . $this->name;
|
||||
if (!empty($this->extension)) {
|
||||
$metaTmpDir .= '.' . $this->extension;
|
||||
}
|
||||
|
||||
return $metaTmpDir;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws MetaException
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get(): array
|
||||
{
|
||||
if (!empty($this->content)) {
|
||||
return $this->content;
|
||||
}
|
||||
$fullFileName = $this->getFullFileName();
|
||||
$metaContent = @file_get_contents($fullFileName);
|
||||
|
||||
$meta = json_decode($metaContent, true);
|
||||
|
||||
if ($meta === null || (json_last_error() !== JSON_ERROR_NONE)
|
||||
) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return $meta;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @throws MetaException
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function update($data = []): bool
|
||||
{
|
||||
if (!$this->save($data)) {
|
||||
return false;
|
||||
}
|
||||
$this->content = $data;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @throws MetaException
|
||||
*
|
||||
* @return false|int
|
||||
*/
|
||||
public function save($data = [])
|
||||
{
|
||||
return file_put_contents($this->getFullFileName(), json_encode($data));
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws MetaException
|
||||
* @return bool
|
||||
*/
|
||||
public function exists(): bool
|
||||
{
|
||||
if (empty($this->name)) {
|
||||
throw new MetaException('Meta file name is not set');
|
||||
}
|
||||
|
||||
return is_file($this->getFullFileName());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $key
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function keyExists($key): bool
|
||||
{
|
||||
$meta = null;
|
||||
try {
|
||||
if ($this->exists()) {
|
||||
$meta = $this->get();
|
||||
}
|
||||
} catch (MetaException $exception) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return null !== $meta && array_key_exists($key, $meta);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws MetaException
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function delete(): bool
|
||||
{
|
||||
if (!$this->exists()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return @unlink($this->getFullFileName());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace Xentral\Modules\Hubspot\Interfaces;
|
||||
|
||||
|
||||
interface HubspotHttpClientInterface
|
||||
{
|
||||
|
||||
const GET_REQUEST = 'GET';
|
||||
const POST_REQUEST = 'POST';
|
||||
const DELETE_REQUEST = 'DELETE';
|
||||
const PATCH_REQUEST = 'PATCH';
|
||||
const PUT_REQUEST = 'PUT';
|
||||
|
||||
//public function get($url, $data = [], $header = []);
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\Hubspot\RequestQueues\Exception;
|
||||
|
||||
use RuntimeException as SplRuntimeException;
|
||||
|
||||
|
||||
class RequestQueuesException extends SplRuntimeException
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\Hubspot\RequestQueues;
|
||||
|
||||
use Xentral\Components\Database\Database;
|
||||
use Xentral\Modules\Hubspot\RequestQueues\Exception\RequestQueuesException;
|
||||
|
||||
final class HubspotRequestQueuesGateway
|
||||
{
|
||||
/** @var Database $db */
|
||||
private $db;
|
||||
|
||||
public function __construct(Database $db)
|
||||
{
|
||||
$this->db = $db;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $type
|
||||
*
|
||||
* @throws RequestQueuesException
|
||||
* @return array
|
||||
*/
|
||||
public function getNewRequestsByCallType($type)
|
||||
{
|
||||
if (!is_string($type)) {
|
||||
throw new RequestQueuesException(
|
||||
'Call Type should be a string'
|
||||
);
|
||||
}
|
||||
$sql = 'SELECT
|
||||
rq.id,
|
||||
rq.command,
|
||||
rq.not_before,
|
||||
rq.try,
|
||||
rq.runner,
|
||||
rq.check_sum,
|
||||
rq.on_after_done
|
||||
FROM hubspot_request_queues AS `rq` WHERE rq.call_type=:type AND rq.completed=0 AND rq.deleted=0
|
||||
ORDER BY rq.created_at';
|
||||
|
||||
return $this->db->fetchAll($sql, ['type' => $type]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,270 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\Hubspot\RequestQueues;
|
||||
|
||||
use ApplicationCore;
|
||||
use Xentral\Components\Database\Database;
|
||||
use Xentral\Components\Database\Exception\DatabaseExceptionInterface;
|
||||
use Xentral\Modules\Hubspot\Exception\HubspotException;
|
||||
use Xentral\Modules\Hubspot\HubspotEventService;
|
||||
use Xentral\Modules\Hubspot\HubspotHttpResponseService;
|
||||
use Xentral\Modules\Hubspot\RequestQueues\Exception\RequestQueuesException;
|
||||
use RuntimeException;
|
||||
|
||||
final class HubspotRequestQueuesService
|
||||
{
|
||||
|
||||
/** @var int */
|
||||
const LOOP_WAITING_TIME = 10000000;
|
||||
/** @var int */
|
||||
const LOOP_BATCH = 1;
|
||||
|
||||
/** @var HubspotRequestQueuesGateway $gateway */
|
||||
private $gateway;
|
||||
/** @var ApplicationCore $app */
|
||||
private $app;
|
||||
|
||||
/** @var Database $db */
|
||||
private $db;
|
||||
|
||||
/** @var array $completedIds */
|
||||
private $completedIds = [];
|
||||
|
||||
/** @var HubspotEventService $eventService */
|
||||
private $eventService;
|
||||
|
||||
/**
|
||||
* @param HubspotRequestQueuesGateway $gateway
|
||||
* @param Database $database
|
||||
* @param ApplicationCore $app
|
||||
* @param HubspotEventService $eventService
|
||||
*/
|
||||
public function __construct(
|
||||
HubspotRequestQueuesGateway $gateway,
|
||||
Database $database,
|
||||
ApplicationCore $app,
|
||||
HubspotEventService $eventService
|
||||
) {
|
||||
$this->gateway = $gateway;
|
||||
$this->app = $app;
|
||||
$this->db = $database;
|
||||
$this->eventService = $eventService;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $option
|
||||
*
|
||||
* @throws RequestQueuesException
|
||||
* @return int
|
||||
*/
|
||||
public function addRequest($option)
|
||||
{
|
||||
$default = ['check_sum' => '', 'command' => '', 'on_after_done' => '', 'not_before' => 0, 'call_type' => ''];
|
||||
$hCommand = [];
|
||||
if (array_key_exists('method', $option)) {
|
||||
$hCommand['method'] = $option['method'];
|
||||
unset($option['method']);
|
||||
}
|
||||
if (array_key_exists('args', $option)) {
|
||||
$hCommand['args'] = $option['args'];
|
||||
unset($option['args']);
|
||||
}
|
||||
if (!empty($hCommand)) {
|
||||
$option['command'] = json_encode($hCommand, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT);
|
||||
}
|
||||
|
||||
if (!empty($option['check_sum'])) {
|
||||
$default['check_sum'] = $option['check_sum'];
|
||||
} else {
|
||||
$default['check_sum'] = array_key_exists('command', $option) ? md5($option['command']) : '';
|
||||
}
|
||||
|
||||
$option = array_merge($default, $option);
|
||||
|
||||
if (!empty($option['on_after_done']) && is_array($option['on_after_done'])) {
|
||||
$option['on_after_done'] = json_encode(
|
||||
$option['on_after_done'],
|
||||
JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT
|
||||
);
|
||||
}
|
||||
|
||||
$check = 'SELECT EXISTS(
|
||||
SELECT id FROM hubspot_request_queues
|
||||
WHERE deleted=0 AND completed=0 AND check_sum=:check_sum AND runner=:runner
|
||||
)';
|
||||
if (empty(
|
||||
$this->db->fetchValue(
|
||||
$check,
|
||||
['runner' => $option['runner'], 'check_sum' => $option['check_sum']]
|
||||
)
|
||||
)) {
|
||||
$add = 'INSERT INTO hubspot_request_queues (command, on_after_done, runner, not_before, check_sum, call_type )
|
||||
VALUES (:command, :on_after_done, :runner, :not_before, :check_sum, :call_type)';
|
||||
try {
|
||||
$this->db->perform($add, $option);
|
||||
} catch (DatabaseExceptionInterface $exception) {
|
||||
throw new RequestQueuesException(json_encode(['too' => $option, $exception->getMessage()]));
|
||||
}
|
||||
|
||||
return $this->db->lastInsertId();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $callType
|
||||
*
|
||||
* @throws HubspotException
|
||||
* @throws RequestQueuesException
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function execute(string $callType): void
|
||||
{
|
||||
$jobs = $this->gateway->getNewRequestsByCallType($callType);
|
||||
if (empty($jobs)) {
|
||||
return;
|
||||
}
|
||||
$batch_loop = self::LOOP_BATCH;
|
||||
$iCount = 0;
|
||||
$bSkippWait = count($jobs) <= 1;
|
||||
foreach ($jobs as $job) {
|
||||
$this->db->perform('UPDATE `hubspot_request_queues` SET try = try+1 WHERE id =:id', ['id' => $job['id']]);
|
||||
$oClass = $this->app->Container->get($job['runner']);
|
||||
$hCommand = json_decode($job['command'], true);
|
||||
if (!is_array($hCommand)) {
|
||||
continue;
|
||||
}
|
||||
$xArg = $hCommand['args'];
|
||||
$sMethod = $hCommand['method'];
|
||||
try {
|
||||
$response = call_user_func_array([$oClass, $sMethod], $xArg);
|
||||
if (empty($response)) {
|
||||
continue;
|
||||
}
|
||||
} catch (RuntimeException $exception) {
|
||||
$this->db->perform(
|
||||
'UPDATE hubspot_request_queues SET completed = 1 WHERE id = :id',
|
||||
['id' => $job['id']]
|
||||
);
|
||||
$this->completedIds[] = $job['id'];
|
||||
$this->eventService->add($exception->getMessage());
|
||||
continue;
|
||||
}
|
||||
$this->onAfterDone($job['id'], $response, $job['on_after_done']);
|
||||
|
||||
if ($bSkippWait === false) {
|
||||
if ($iCount === $batch_loop) {
|
||||
$batch_loop += self::LOOP_BATCH;
|
||||
@usleep(self::LOOP_WAITING_TIME);
|
||||
}
|
||||
echo 'Script always alive... ';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $id
|
||||
* @param HubspotHttpResponseService|null $response
|
||||
* @param string $onAfter
|
||||
*
|
||||
* @throws HubspotException
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function onAfterDone(int $id, ?HubspotHttpResponseService $response, string $onAfter = ''): void
|
||||
{
|
||||
$onAfterData = !empty($onAfter) ? json_decode($onAfter, true) : [];
|
||||
|
||||
if (!empty($onAfterData) && array_key_exists('runner', $onAfterData) && array_key_exists(
|
||||
'method',
|
||||
$onAfterData
|
||||
) && array_key_exists('args', $onAfterData) && $this->app->Container->has($onAfterData['runner'])) {
|
||||
$oClass = $this->app->Container->get($onAfterData['runner']);
|
||||
if (!empty($onAfterData['replace_in_args']) && in_array($response->getStatusCode(), [200, 204], true)) {
|
||||
$hasDataFetcher = !empty($onAfterData['data_fetcher']) && method_exists(
|
||||
$this,
|
||||
$onAfterData['data_fetcher']
|
||||
);
|
||||
$jsonData = $hasDataFetcher === true ? $this->{$onAfterData['data_fetcher']}(
|
||||
$response
|
||||
) : $response->getJson();
|
||||
if (empty($jsonData)) {
|
||||
return;
|
||||
}
|
||||
foreach ($onAfterData['args'] as &$xArg) {
|
||||
if (is_string($xArg)) {
|
||||
foreach ($onAfterData['replace_in_args'] as $replace_with) {
|
||||
if (!empty($jsonData[$replace_with])) {
|
||||
$xArg = sprintf($xArg, $jsonData[$replace_with]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
call_user_func_array(
|
||||
[$oClass, $onAfterData['method']],
|
||||
$onAfterData['args']
|
||||
);
|
||||
}
|
||||
|
||||
if (array_key_exists('event', $onAfterData) &&
|
||||
!empty($onAfterData['event']) &&
|
||||
is_string($onAfterData['event']) &&
|
||||
in_array($response->getStatusCode(), [200, 204], true)
|
||||
) {
|
||||
$this->eventService->add($onAfterData['event']);
|
||||
}
|
||||
if (array_key_exists('other_event', $onAfterData)) {
|
||||
$other = $onAfterData['other_event'];
|
||||
if (!empty($other) && $this->app->Container->has($other['runner'])) {
|
||||
$otherEventClass = $this->app->Container->get($other['runner']);
|
||||
call_user_func_array(
|
||||
[$otherEventClass, $other['method']],
|
||||
$other['args']
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (is_numeric($id)) {
|
||||
$this->db->perform('UPDATE hubspot_request_queues SET completed = 1 WHERE id = :id', ['id' => $id]);
|
||||
$this->completedIds[] = $id;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function cleanup()
|
||||
{
|
||||
foreach ($this->completedIds as $completedId) {
|
||||
echo $completedId;
|
||||
$this->db->perform(
|
||||
'DELETE FROM hubspot_request_queues WHERE id=:id AND completed=1',
|
||||
['id' => $completedId]
|
||||
);
|
||||
}
|
||||
$this->eventService->deleteByInterval();
|
||||
unset($this->completedIds);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param HubspotHttpResponseService $response
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function getEngagement(HubspotHttpResponseService $response): array
|
||||
{
|
||||
if ($response->getStatusCode() !== 200) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$result = $response->getJson();
|
||||
if (!array_key_exists('engagement', $result)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return $result['engagement'];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\Hubspot\Scheduler\Adapter;
|
||||
|
||||
use ArrayObject;
|
||||
use Xentral\Modules\Hubspot\Exception\SchedulerAdapterBadMethodException;
|
||||
use Xentral\Modules\Hubspot\Scheduler\HubspotSchedulerTaskInterface;
|
||||
|
||||
final class SchedulerAdapter
|
||||
{
|
||||
/** @var HubspotSchedulerTaskInterface $schedulerTask */
|
||||
private $schedulerTask;
|
||||
|
||||
/** @var bool $debugMode */
|
||||
public $debugMode = false;
|
||||
|
||||
public function __construct(HubspotSchedulerTaskInterface $schedulerTask)
|
||||
{
|
||||
$this->schedulerTask = $schedulerTask;
|
||||
}
|
||||
|
||||
public function __call($method, $args)
|
||||
{
|
||||
if (!method_exists($this->schedulerTask, $method)) {
|
||||
$class = get_class($this->schedulerTask);
|
||||
throw new SchedulerAdapterBadMethodException(sprintf('Method %s at %s class is missing', $method, $class));
|
||||
}
|
||||
|
||||
if (is_callable([$this->schedulerTask, $method])) {
|
||||
if ($method === 'execute' && empty($args) === true) {
|
||||
$this->schedulerTask->beforeScheduleAction(new ArrayObject($args));
|
||||
}
|
||||
if ($this->debugMode === true) {
|
||||
$this->debug(json_encode(new ArrayObject($args)));
|
||||
$message = 'Call ' . get_class($this->schedulerTask) . '::' . $method . ' with args ' . json_encode(
|
||||
$args
|
||||
);
|
||||
$this->debug($message);
|
||||
}
|
||||
call_user_func([$this->schedulerTask, $method], $args);
|
||||
if ($method === 'execute' && empty($args) === true) {
|
||||
$this->schedulerTask->afterScheduleAction(new ArrayObject($args));
|
||||
}
|
||||
} else {
|
||||
$class = get_class($this->schedulerTask);
|
||||
throw new SchedulerAdapterBadMethodException(sprintf('No callable method %s at %s class', $method, $class));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $message
|
||||
* @param null|string $debuggerFile
|
||||
*
|
||||
* @return null|void
|
||||
*/
|
||||
public function debug($message, $debuggerFile = null)
|
||||
{
|
||||
if ($this->debugMode === false) {
|
||||
return null;
|
||||
}
|
||||
$logFile = null === $debuggerFile ? sys_get_temp_dir() . '/pull.log' : $debuggerFile;
|
||||
file_put_contents($logFile, date('Y-m-d H:i:s') . '- ' . $message . "\n", FILE_APPEND | LOCK_EX);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\Hubspot\Scheduler;
|
||||
|
||||
use ArrayObject;
|
||||
use Xentral\Modules\Hubspot\RequestQueues\HubspotRequestQueuesService;
|
||||
use Xentral\Modules\SubscriptionCycle\Scheduler\TaskMutexServiceInterface;
|
||||
|
||||
final class HubspotProcessSchedulerTask implements HubspotSchedulerTaskInterface
|
||||
{
|
||||
const CALL_TYPE = 'hubspot';
|
||||
/** @var HubspotRequestQueuesService $gateway */
|
||||
private $service;
|
||||
|
||||
/** @var TaskMutexServiceInterface $taskMutexService */
|
||||
private $taskMutexService;
|
||||
|
||||
/**
|
||||
* @param HubspotRequestQueuesService $service
|
||||
* @param TaskMutexServiceInterface $taskMutexService
|
||||
*/
|
||||
public function __construct(HubspotRequestQueuesService $service, TaskMutexServiceInterface $taskMutexService)
|
||||
{
|
||||
$this->service = $service;
|
||||
$this->taskMutexService = $taskMutexService;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function execute()
|
||||
{
|
||||
if ($this->taskMutexService->isTaskInstanceRunning('hubspot_process')) {
|
||||
return;
|
||||
}
|
||||
$this->taskMutexService->setMutex('hubspot_process');
|
||||
|
||||
$this->service->execute(static::CALL_TYPE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function cleanup()
|
||||
{
|
||||
$this->taskMutexService->setMutex('hubspot_process', false);
|
||||
$this->service->cleanup();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ArrayObject $args
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function beforeScheduleAction(ArrayObject $args)
|
||||
{
|
||||
// TODO: Implement beforeScheduleAction() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ArrayObject $args
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function afterScheduleAction(ArrayObject $args)
|
||||
{
|
||||
// TODO: Implement afterScheduleAction() method.
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,866 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\Hubspot\Scheduler;
|
||||
|
||||
use JsonException;
|
||||
use Xentral\Components\Database\Database;
|
||||
use Xentral\Components\Database\Exception\EscapingException;
|
||||
use Xentral\Modules\Country\Gateway\CountryGateway;
|
||||
use Xentral\Modules\Hubspot\Exception\HubspotConfigurationServiceException;
|
||||
use Xentral\Modules\Hubspot\Exception\HubspotException;
|
||||
use Xentral\Modules\Hubspot\Exception\MetaException;
|
||||
use Xentral\Modules\Hubspot\HubspotConfigurationService;
|
||||
use Xentral\Modules\Hubspot\HubspotContactService;
|
||||
use Xentral\Modules\Hubspot\HubspotEventService;
|
||||
use Xentral\Modules\Hubspot\HubspotContactGateway;
|
||||
use Xentral\Modules\Hubspot\HubspotMetaService;
|
||||
|
||||
use ArrayObject;
|
||||
use Xentral\Modules\SubscriptionCycle\Scheduler\TaskMutexServiceInterface;
|
||||
|
||||
final class HubspotPullContactsTask implements HubspotSchedulerTaskInterface
|
||||
{
|
||||
|
||||
/** @var HubspotContactService $contactService */
|
||||
private $contactService;
|
||||
|
||||
/** @var Database $db */
|
||||
private $db;
|
||||
|
||||
/** @var HubspotMetaService $meta */
|
||||
private $meta;
|
||||
|
||||
/** @var HubspotContactGateway $gateway */
|
||||
private $gateway;
|
||||
|
||||
/** @var HubspotConfigurationService $configuration */
|
||||
private $configuration;
|
||||
|
||||
/** @var HubspotEventService $eventService */
|
||||
private $eventService;
|
||||
|
||||
/** @var CountryGateway $countryGateway */
|
||||
private $countryGateway;
|
||||
|
||||
/** @var TaskMutexServiceInterface $taskMutexService */
|
||||
private $taskMutexService;
|
||||
|
||||
/** @var bool $mutexOn */
|
||||
private $mutexOn = false;
|
||||
|
||||
/**
|
||||
* @param HubspotContactService $contactService
|
||||
* @param Database $db
|
||||
* @param HubspotMetaService $metaService
|
||||
* @param HubspotContactGateway $gateway
|
||||
* @param HubspotConfigurationService $configuration
|
||||
* @param HubspotEventService $eventService
|
||||
* @param CountryGateway $countryGateway
|
||||
* @param TaskMutexServiceInterface $taskMutexService
|
||||
*/
|
||||
public function __construct(
|
||||
HubspotContactService $contactService,
|
||||
Database $db,
|
||||
HubspotMetaService $metaService,
|
||||
HubspotContactGateway $gateway,
|
||||
HubspotConfigurationService $configuration,
|
||||
HubspotEventService $eventService,
|
||||
CountryGateway $countryGateway,
|
||||
TaskMutexServiceInterface $taskMutexService
|
||||
) {
|
||||
$this->db = $db;
|
||||
$this->contactService = $contactService;
|
||||
$this->meta = $metaService;
|
||||
$this->gateway = $gateway;
|
||||
$this->configuration = $configuration;
|
||||
$this->eventService = $eventService;
|
||||
$this->countryGateway = $countryGateway;
|
||||
$this->taskMutexService = $taskMutexService;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $option
|
||||
* @param null $type
|
||||
* @param false $recursiveMode
|
||||
*
|
||||
* @throws EscapingException
|
||||
* @throws HubspotConfigurationServiceException
|
||||
* @throws HubspotException
|
||||
* @throws JsonException
|
||||
* @throws MetaException
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function execute($option = [], $type = null, $recursiveMode = false): void
|
||||
{
|
||||
if ($recursiveMode === false && $this->mutexOn === false) {
|
||||
if ($this->taskMutexService->isTaskInstanceRunning('hubspot_pull_contacts')) {
|
||||
return;
|
||||
}
|
||||
$this->taskMutexService->setMutex('hubspot_pull_contacts');
|
||||
$this->mutexOn = true;
|
||||
}
|
||||
|
||||
$settings = $this->configuration->getSettings();
|
||||
if ($settings['hs_sync_addresses'] !== true) {
|
||||
return;
|
||||
}
|
||||
$contactType = $type ?? 'all';
|
||||
|
||||
if (empty($recursiveMode) && $this->hasHsContacts() === true) {
|
||||
$contactType = $contactType === 'all' ? 'recently_updated' : $contactType;
|
||||
}
|
||||
|
||||
if ($contactType === 'company') {
|
||||
$contactType = 'companies';
|
||||
}
|
||||
|
||||
$ret = $this->pull($contactType, $option);
|
||||
if (!empty($ret['has_more'])) {
|
||||
$option = ['vidOffset' => $ret['vidOffset'], 'timeOffset' => $ret['timeOffset']];
|
||||
usleep(5000000);
|
||||
$this->execute($option, $contactType, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $option
|
||||
* @param null $type
|
||||
* @param false $recursiveMode
|
||||
*
|
||||
* @throws EscapingException
|
||||
* @throws HubspotConfigurationServiceException
|
||||
* @throws HubspotException
|
||||
* @throws JsonException
|
||||
* @throws MetaException
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function executeForCompany($option = [], $type = null, $recursiveMode = false): void
|
||||
{
|
||||
if ($recursiveMode === false && $this->mutexOn === false) {
|
||||
if ($this->taskMutexService->isTaskInstanceRunning('hubspot_pull_contacts')) {
|
||||
return;
|
||||
}
|
||||
$this->taskMutexService->setMutex('hubspot_pull_contacts');
|
||||
$this->mutexOn = true;
|
||||
}
|
||||
$settings = $this->configuration->getSettings();
|
||||
if ($settings['hs_sync_addresses'] !== true) {
|
||||
return;
|
||||
}
|
||||
$contactType = $type ?? 'company';
|
||||
|
||||
|
||||
if (empty($recursiveMode) && $this->hasHsContacts() === true) {
|
||||
$contactType = $contactType === 'company' ? 'recent_companies' : $contactType;
|
||||
}
|
||||
|
||||
$ret = $this->pull($contactType, $option);
|
||||
|
||||
if (!empty($ret['has_more'])) {
|
||||
$option = ['vidOffset' => $ret['vidOffset'], 'timeOffset' => $ret['timeOffset']];
|
||||
usleep(5000000);
|
||||
$this->executeForCompany($option, $contactType, true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $type
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function hasHsContacts(string $type = 'address'): bool
|
||||
{
|
||||
return $this->db->fetchValue(
|
||||
'SELECT COUNT(`id`) FROM `hubspot_contacts` WHERE `hidden` = 0 AND `type` = :type',
|
||||
['type' => $type]
|
||||
) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $email
|
||||
* @param int $addressId
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function contactPersonExists(string $email, int $addressId): bool
|
||||
{
|
||||
return $this->db->fetchValue(
|
||||
'SELECT `id` FROM `ansprechpartner` WHERE `email` = :email AND `adresse` = :addressId',
|
||||
['email' => $email, 'addressId' => $addressId]
|
||||
) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
private function getAddressIdByCompanyName(string $name): int
|
||||
{
|
||||
return $this->db->fetchValue(
|
||||
"SELECT ad.id FROM `adresse` AS `ad` JOIN `hubspot_contacts` AS `hs`
|
||||
ON(ad.id = hs.address_id)
|
||||
WHERE ad.firma = 1 AND
|
||||
ad.typ = 'firma' AND
|
||||
hs.type = 'company' AND
|
||||
ad.name = :name LIMIT 1",
|
||||
['name' => $name]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function cleanup(): void
|
||||
{
|
||||
$this->taskMutexService->setMutex('hubspot_pull_contacts', false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $companies
|
||||
*
|
||||
* @throws HubspotException
|
||||
* @throws EscapingException
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function importCompany(array $companies): void
|
||||
{
|
||||
$settings = $this->configuration->getSettings();
|
||||
foreach ($companies as $company) {
|
||||
$companyId = $company['companyId'];
|
||||
|
||||
if ($this->gateway->getMappingByHubspotId($companyId, 'company')) {
|
||||
$this->updateXTContact($companyId, 'company');
|
||||
continue;
|
||||
}
|
||||
$properties = $company['properties'];
|
||||
$companyData = array_combine(array_keys($properties), array_column($properties, 'value'));
|
||||
$companyNameTag = $properties['name'];
|
||||
$contactSourceIds = array_combine(array_keys($properties), array_column($properties, 'sourceId'));
|
||||
$hsLeadStatus = array_key_exists('hs_lead_status', $companyData) ? $companyData['hs_lead_status'] : '';
|
||||
$createdAt = $companyNameTag['timestamp'];
|
||||
$sourceEmail = $companyNameTag['sourceId'];
|
||||
if (empty($sourceEmail)) {
|
||||
$sourceEmail = $contactSourceIds['name'];
|
||||
}
|
||||
|
||||
$country = empty($companyData['country']) ? 'DE' : $companyData['country'];
|
||||
if ($country !== 'DE') {
|
||||
$countryDb = $this->countryGateway->findByName($country);
|
||||
if (!empty($countryDb)) {
|
||||
$country = $countryDb['iso2_code'];
|
||||
}
|
||||
}
|
||||
$address = [
|
||||
'typ' => 'firma',
|
||||
'sprache' => 'deutsch',
|
||||
'name' => $companyData['name'],
|
||||
'land' => $country,
|
||||
'email' => $sourceEmail,
|
||||
'kundenfreigabe' => 1,
|
||||
'firma' => 1,
|
||||
'waehrung' => 'EUR',
|
||||
'internetseite' => empty($companyData['website']) ? '' : $companyData['website'],
|
||||
'ort' => empty($companyData['city']) ? '' : $companyData['city'],
|
||||
'plz' => empty($companyData['zip']) ? '' : $companyData['zip'],
|
||||
'strasse' => empty($companyData['address']) ? '' : $companyData['address'],
|
||||
];
|
||||
|
||||
try {
|
||||
$leadFields = $this->configuration->matchSelectedAddressFreeField();
|
||||
$lrField = $leadFields['hubspot_lr_field'];
|
||||
$lsField = $leadFields['hubspot_ls_field'];
|
||||
$address[$lsField] = $hsLeadStatus;
|
||||
$address[$lrField] = empty($companyData['lifecyclestage']) ? '' : $companyData['lifecyclestage'];
|
||||
} catch (HubspotException $exception) {
|
||||
$this->eventService->add($exception->getMessage());
|
||||
}
|
||||
|
||||
$numberOfEmployeesField = $this->configuration->tryGetConfiguration('hubspot_numberofemployees_field');
|
||||
if (!empty($numberOfEmployeesField)) {
|
||||
$fieldName = str_replace('adresse', '', $numberOfEmployeesField);
|
||||
$numberOfEmployees = empty($companyData['numberofemployees']) ? 0 : $companyData['numberofemployees'];
|
||||
$address[$fieldName] = $numberOfEmployees;
|
||||
}
|
||||
|
||||
$defaultCustomFields = array_key_exists('hubspot_address_free_fields', $settings) ?
|
||||
$settings['hubspot_address_free_fields'] : [];
|
||||
if (!empty($defaultCustomFields)) {
|
||||
foreach ($defaultCustomFields as $defaultCustomField => $systemField) {
|
||||
$fieldName = str_replace('adresse', '', $systemField);
|
||||
$fieldValue = empty($companyData[$defaultCustomField]) ? '' : $companyData[$defaultCustomField];
|
||||
$address[$fieldName] = $fieldValue;
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($createdAt) &&
|
||||
array_key_exists('hs_sync_addresses_from', $settings) &&
|
||||
!empty($settings['hs_sync_addresses_from'])
|
||||
) {
|
||||
$addedTime = $createdAt / 1000;
|
||||
if ($addedTime < $settings['hs_sync_addresses_from']) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// Status
|
||||
if (array_key_exists('hs_sync_address_status', $settings) &&
|
||||
!empty($settings['hs_sync_address_status']) &&
|
||||
$hsLeadStatus !== $settings['hs_sync_address_status']
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$hubspotOwnerId = (int)array_key_exists(
|
||||
'hubspot_owner_id',
|
||||
$companyData
|
||||
) ? $companyData['hubspot_owner_id'] : 0;
|
||||
if ($hubspotOwnerId !== 0) {
|
||||
$staffId = $this->manageSaleStaffPerson($companyId, $hubspotOwnerId);
|
||||
if ($staffId !== 0) {
|
||||
$address['vertrieb'] = $staffId;
|
||||
}
|
||||
}
|
||||
|
||||
$this->addXTContact($companyId, 'company', $address);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $type
|
||||
* @param array $options
|
||||
*
|
||||
* @throws EscapingException
|
||||
* @throws HubspotConfigurationServiceException
|
||||
* @throws HubspotException
|
||||
* @throws MetaException
|
||||
* @throws JsonException
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function pull($type = 'recently_updated', $options = []): array
|
||||
{
|
||||
$response = in_array($type, ['company', 'recent_companies']) ?
|
||||
$this->contactService->pullCompanies($type, $options) :
|
||||
$this->contactService->pullContacts($type, $options);
|
||||
|
||||
if ($response->getStatusCode() !== 200) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$data = $response->getJson();
|
||||
$offSet = array_key_exists('vid-offset', $data) ? $data['vid-offset'] : 0;
|
||||
$singleOffset = array_key_exists('offset', $data) ? $data['offset'] : -1;
|
||||
$hasMore = array_key_exists('has-more', $data) ? $data['has-more'] : false;
|
||||
$timeOffset = array_key_exists('time-offset', $data) ? $data['time-offset'] : 0;
|
||||
if (array_key_exists('companies', $data) || $type === 'recent_companies') {
|
||||
$companyResponse = $type !== 'recent_companies' ? $data['companies'] : $data['results'];
|
||||
$this->importCompany($companyResponse);
|
||||
}
|
||||
|
||||
if (array_key_exists('contacts', $data)) {
|
||||
$settings = $this->configuration->getSettings();
|
||||
$contacts = $data['contacts'];
|
||||
if (count($contacts) > 0) {
|
||||
foreach ($contacts as $contact) {
|
||||
$contactId = $contact['vid'];
|
||||
$properties = $contact['properties'];
|
||||
$createdAt = $contact['addedAt'];
|
||||
$contactData = array_combine(array_keys($properties), array_column($properties, 'value'));
|
||||
$hsLeadStatus = array_key_exists('hs_lead_status', $contactData) ?
|
||||
$contactData['hs_lead_status'] : '';
|
||||
$email = '';
|
||||
|
||||
$identityProfile = $contact['identity-profiles'];
|
||||
if (!empty($identityProfile)) {
|
||||
$identities = array_column($identityProfile, 'identities');
|
||||
foreach ($identities as $identity) {
|
||||
foreach ($identity as $item) {
|
||||
if ($item['type'] === 'EMAIL') {
|
||||
$email = $item['value'];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$contactCompany = array_key_exists('company', $contactData) ? $contactData['company'] : '';
|
||||
|
||||
if (!empty($contactCompany) && ($addressId = $this->getAddressIdByCompanyName(
|
||||
$contactCompany
|
||||
))) {
|
||||
$contactPerson = [
|
||||
'type' => 'herr',
|
||||
'name' => sprintf(
|
||||
'%s %s',
|
||||
empty($contactData['firstname']) ? 'Hubspot - ' : $contactData['firstname'],
|
||||
empty($contactData['lastname']) ? '' : $contactData['lastname']
|
||||
),
|
||||
'adresse' => $addressId,
|
||||
'email' => $email,
|
||||
'land' => 'DE',
|
||||
'phone' => $contactData['phone'],
|
||||
];
|
||||
|
||||
if ($this->contactPersonExists($email, $addressId) === true) {
|
||||
continue;
|
||||
}
|
||||
$this->addContactPerson($contactPerson, $contactId);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($this->gateway->getMappingByHubspotId($contactId)) {
|
||||
// UPDATE
|
||||
if ($type === 'recently_updated') {
|
||||
$this->updateXTContact($contactId);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!empty($createdAt) &&
|
||||
array_key_exists('hs_sync_addresses_from', $settings) &&
|
||||
!empty($settings['hs_sync_addresses_from'])
|
||||
) {
|
||||
$addedTime = $createdAt / 1000;
|
||||
if ($addedTime < $settings['hs_sync_addresses_from']) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// Status
|
||||
if (array_key_exists('hs_sync_address_status', $settings) &&
|
||||
!empty($settings['hs_sync_address_status']) &&
|
||||
$hsLeadStatus !== $settings['hs_sync_address_status']
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->addXTContact($contactId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($timeOffset === 0) {
|
||||
$timeOffset = time() * 1000;
|
||||
}
|
||||
|
||||
$remainingData = ['vidOffset' => $offSet, 'timeOffset' => $timeOffset];
|
||||
if ($singleOffset !== -1) {
|
||||
$remainingData['offset'] = $singleOffset;
|
||||
}
|
||||
$this->meta->setName($type)->save($remainingData);
|
||||
$remainingData['has_more'] = $hasMore;
|
||||
|
||||
return $remainingData;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $contactId
|
||||
* @param string $type
|
||||
* @param array $contact
|
||||
*
|
||||
* @throws HubspotException
|
||||
* @throws EscapingException
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function addXTContact(int $contactId = 0, string $type = 'address', array $contact = []): void
|
||||
{
|
||||
$addressContact = $contact;
|
||||
if (empty($contact)) {
|
||||
$addressContact = $this->configuration->formatAddressByResponse(
|
||||
$this->contactService->getContactById($contactId)
|
||||
);
|
||||
}
|
||||
if (empty($addressContact)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$hubspotOwnerId = (int)$addressContact['hubspot_owner_id'];
|
||||
unset($addressContact['hubspot_owner_id']);
|
||||
if ($hubspotOwnerId !== 0) {
|
||||
$staffId = $this->manageSaleStaffPerson($contactId, $hubspotOwnerId);
|
||||
if ($staffId !== 0) {
|
||||
$addressContact['vertrieb'] = $staffId;
|
||||
}
|
||||
}
|
||||
|
||||
$paramValues = array_map(
|
||||
function ($value) {
|
||||
if (empty($value)) {
|
||||
return '\'\'';
|
||||
}
|
||||
|
||||
return is_string($value) ? $this->db->escapeString($value) : $value;
|
||||
},
|
||||
array_values($addressContact)
|
||||
);
|
||||
$placeHolders = implode(',', array_fill(0, count($paramValues), '%s'));
|
||||
|
||||
$sql = 'INSERT INTO adresse(' . implode(',', array_keys($addressContact)) . ')
|
||||
VALUES(' . vsprintf($placeHolders, $paramValues) . ')';
|
||||
$this->db->perform($sql);
|
||||
if ($addressId = $this->db->lastInsertId()) {
|
||||
$this->db->perform(
|
||||
'INSERT INTO `hubspot_contacts` (`hs_contact_id`, `created_at`, `address_id`, `type`)
|
||||
VALUES (:id, NOW(), :aid, :type)',
|
||||
['id' => $contactId, 'aid' => $addressId, 'type' => $type]
|
||||
);
|
||||
$eventItem = !empty($addressContact['email']) ? $addressContact['email'] : $addressContact['name'];
|
||||
|
||||
$eventMsg = sprintf(
|
||||
'Neuen Kontakt (<a href="/index.php?module=adresse&action=edit&id=%d">%s</a>) vom Hubspot hinzugefügt ins Xentral importiert.',
|
||||
$addressId,
|
||||
$eventItem
|
||||
);
|
||||
$this->eventService->add($eventMsg);
|
||||
// ADD to group
|
||||
$this->configuration->addContactToGroup($addressId);
|
||||
// get companies contacts
|
||||
if ($type === 'company') {
|
||||
$this->importCompanyContactPersons($contactId, $addressId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $hubspotContactId
|
||||
* @param string|null $type
|
||||
*
|
||||
* @throws HubspotException
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function updateXTContact(int $hubspotContactId = 0, ?string $type = 'address'): void
|
||||
{
|
||||
$remoteResponse = $type === 'company' ? $this->contactService->getCompanyById($hubspotContactId) :
|
||||
$this->contactService->getContactById($hubspotContactId);
|
||||
if ($remoteResponse->getStatusCode() !== 200) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
$xtContact = $type === 'company' ? $this->configuration->formatCompanyByResponse($remoteResponse) :
|
||||
$this->configuration->formatAddressByResponse($remoteResponse);
|
||||
} catch (HubspotException $exception) {
|
||||
$this->eventService->add($exception->getMessage());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$excludeVars = ['lead', 'typ', 'sprache', 'waehrung', 'kundenfreigabe'];
|
||||
foreach ($excludeVars as $excludeVar) {
|
||||
if (array_key_exists($excludeVar, $xtContact)) {
|
||||
unset($xtContact[$excludeVar]);
|
||||
}
|
||||
}
|
||||
|
||||
$hubspotOwnerId = (int)$xtContact['hubspot_owner_id'];
|
||||
unset($xtContact['hubspot_owner_id']);
|
||||
if ($hubspotOwnerId !== 0) {
|
||||
$staffId = $this->manageSaleStaffPerson($hubspotContactId, $hubspotOwnerId);
|
||||
if ($staffId !== 0) {
|
||||
$xtContact['vertrieb'] = $staffId;
|
||||
}
|
||||
}
|
||||
$hHSContact = $this->gateway->getMappingByHubspotId($hubspotContactId, $type);
|
||||
if (empty($hHSContact)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$asPlaceHolders = array_map(
|
||||
static function ($val) {
|
||||
return vsprintf('%s=:%s', [$val, $val]);
|
||||
},
|
||||
array_keys($xtContact)
|
||||
);
|
||||
|
||||
$placeHolders = implode(',', $asPlaceHolders);
|
||||
|
||||
$affected = $this->db->fetchAffected(
|
||||
'UPDATE adresse SET ' . $placeHolders . ' WHERE id=' . $hHSContact['address_id'],
|
||||
$xtContact
|
||||
);
|
||||
$eventItem = !empty($xtContact['email']) ? $xtContact['email'] : $xtContact['name'];
|
||||
if ($affected > 0) {
|
||||
$eventMsg = sprintf(
|
||||
'Kontakt (<a href="/index.php?module=adresse&action=edit&id=%d">%s</a>) vom Hubspot geändert und ins Xentral importiert',
|
||||
$hHSContact['address_id'],
|
||||
$eventItem
|
||||
);
|
||||
$this->eventService->add($eventMsg);
|
||||
}
|
||||
if ($type === 'company') {
|
||||
$this->importCompanyContactPersons($hubspotContactId, $hHSContact['address_id']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ArrayObject $args
|
||||
*
|
||||
* @throws EscapingException
|
||||
* @throws HubspotConfigurationServiceException
|
||||
* @throws HubspotException
|
||||
* @throws JsonException
|
||||
* @throws MetaException
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function beforeScheduleAction(ArrayObject $args): void
|
||||
{
|
||||
if (empty($this->configuration->tryGetConfiguration(HubspotConfigurationService::HUBSPOT_SALT_CONF_NAME))) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
$leadsFields = $this->configuration->matchSelectedAddressFreeField();
|
||||
} catch (HubspotException $exception) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (empty($leadsFields)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->executeForCompany();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $contactPerson
|
||||
* @param int $hubspotContactPersonId
|
||||
*
|
||||
* @throws HubspotConfigurationServiceException
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function addContactPerson(array $contactPerson, int $hubspotContactPersonId = 0): void
|
||||
{
|
||||
$this->db->perform(
|
||||
'INSERT INTO `ansprechpartner` (
|
||||
`typ`,
|
||||
`name`,
|
||||
`adresse`,
|
||||
`email`,
|
||||
`land`,
|
||||
`logdatei`,
|
||||
`telefon`
|
||||
)
|
||||
VALUES (:type, :name, :adresse, :email, :land, NOW(), :phone)',
|
||||
$contactPerson
|
||||
);
|
||||
|
||||
$companyContactPersonId = $this->db->lastInsertId();
|
||||
if (empty($companyContactPersonId) || empty($hubspotContactPersonId)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$contactExists = $this->gateway->hubspotContactExists($hubspotContactPersonId, ['address', 'person']);
|
||||
if ($contactExists === true) {
|
||||
$sql = 'UPDATE `hubspot_contacts` SET `type` = :type, `address_id` = :aid WHERE `hs_contact_id` = :id';
|
||||
$this->db->perform(
|
||||
$sql,
|
||||
[
|
||||
'id' => $hubspotContactPersonId,
|
||||
'aid' => $companyContactPersonId,
|
||||
'type' => 'person',
|
||||
]
|
||||
);
|
||||
} else {
|
||||
$this->db->perform(
|
||||
'INSERT INTO `hubspot_contacts` (`hs_contact_id`, `created_at`, `address_id`, `type`)
|
||||
VALUES (:id, NOW(), :aid, :type)',
|
||||
['id' => $hubspotContactPersonId, 'aid' => $companyContactPersonId, 'type' => 'person']
|
||||
);
|
||||
}
|
||||
if ($this->isContactPersonInHubspotGroup($companyContactPersonId) === false) {
|
||||
$this->addContactPersonToHubspotGroup($companyContactPersonId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $contactPersonId
|
||||
*
|
||||
* @throws HubspotConfigurationServiceException
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function addContactPersonToHubspotGroup(int $contactPersonId): void
|
||||
{
|
||||
$defaultSettings = $this->configuration->getSettings();
|
||||
|
||||
$contactGrpId = array_key_exists('hs_contact_grp', $defaultSettings) ? $defaultSettings['hs_contact_grp'] : 0;
|
||||
if (empty($contactGrpId)) {
|
||||
return;
|
||||
}
|
||||
$sql = 'INSERT INTO `ansprechpartner_gruppen` (`ansprechpartner`, `gruppe`, `aktiv`) VALUES (:id, :group, 1)';
|
||||
$this->db->perform($sql, ['id' => $contactPersonId, 'group' => $contactGrpId]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $contactPersonId
|
||||
*
|
||||
* @throws HubspotConfigurationServiceException
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function isContactPersonInHubspotGroup(int $contactPersonId): bool
|
||||
{
|
||||
$defaultSettings = $this->configuration->getSettings();
|
||||
|
||||
$contactGrpId = array_key_exists('hs_contact_grp', $defaultSettings) ? $defaultSettings['hs_contact_grp'] : 0;
|
||||
if (empty($contactGrpId)) {
|
||||
return true;
|
||||
}
|
||||
$sql = 'SELECT `id` FROM `ansprechpartner_gruppen` WHERE `ansprechpartner` = :id AND `gruppe` = :group';
|
||||
$result = $this->db->fetchValue($sql, ['id' => $contactPersonId, 'group' => $contactGrpId]);
|
||||
|
||||
return !empty($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $internalContactPersonId
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function mapPersonToCompany(int $internalContactPersonId): void
|
||||
{
|
||||
$mappingData = $this->gateway->getHubspotMappingByPersonId($internalContactPersonId);
|
||||
if (empty($mappingData)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (empty($mappingData['company_id']) || empty($mappingData['contact_id'])) {
|
||||
return;
|
||||
}
|
||||
$this->contactService->addContactToCompany($mappingData['company_id'], $mappingData['contact_id']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $companyId
|
||||
* @param int $addressId
|
||||
*
|
||||
* @throws HubspotConfigurationServiceException
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function importCompanyContactPersons(int $companyId, int $addressId): void
|
||||
{
|
||||
$contactPersonsResponse = $this->contactService->getCompanyContacts($companyId);
|
||||
if ($contactPersonsResponse->getStatusCode() !== 200) {
|
||||
return;
|
||||
}
|
||||
$contactPersonsData = $contactPersonsResponse->getJson();
|
||||
if (empty($contactPersonsData['contacts'])) {
|
||||
return;
|
||||
}
|
||||
$contactPersons = $contactPersonsData['contacts'];
|
||||
foreach ($contactPersons as $contactPerson) {
|
||||
$email = '';
|
||||
$identities = $contactPerson['identities'];
|
||||
$contactPersonVid = array_column($identities, 'vid');
|
||||
$rawContact = [];
|
||||
$contactPersonId = 0;
|
||||
if (!empty($contactPersonVid)) {
|
||||
$contactPersonId = $contactPersonVid[0];
|
||||
$hubspotContactResponse = $this->contactService->getContactById($contactPersonId);
|
||||
if ($hubspotContactResponse->getStatusCode() !== 200) {
|
||||
continue;
|
||||
}
|
||||
$contactJs = $hubspotContactResponse->getJson();
|
||||
$properties = $contactJs['properties'];
|
||||
$rawContact = array_combine(
|
||||
array_keys($properties),
|
||||
array_column($properties, 'value')
|
||||
);
|
||||
$email = array_key_exists('email', $rawContact) ? $rawContact['email'] : '';
|
||||
}
|
||||
if (empty($rawContact)) {
|
||||
$contactPersonIdentity = array_column($identities, 'identity');
|
||||
foreach ($contactPersonIdentity as $identity) {
|
||||
foreach ($identity as $item) {
|
||||
if ($item['type'] === 'EMAIL') {
|
||||
$email = $item['value'];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
$properties = $contactPerson['properties'];
|
||||
$rawContact = array_combine(
|
||||
array_column($properties, 'name'),
|
||||
array_column($properties, 'value')
|
||||
);
|
||||
}
|
||||
$contactPersonForDB = [
|
||||
'type' => 'herr',
|
||||
'name' => sprintf(
|
||||
'%s %s',
|
||||
empty($rawContact['firstname']) ? 'Hubspot - ' : $rawContact['firstname'],
|
||||
empty($rawContact['lastname']) ? '' : $rawContact['lastname']
|
||||
),
|
||||
'adresse' => $addressId,
|
||||
'email' => $email,
|
||||
'land' => 'DE',
|
||||
'phone' => empty($rawContact['phone']) ? '' : $rawContact['phone'],
|
||||
];
|
||||
|
||||
if ($this->contactPersonExists($email, $addressId) === true) {
|
||||
continue;
|
||||
}
|
||||
$this->addContactPerson($contactPersonForDB, $contactPersonId);
|
||||
}
|
||||
}
|
||||
|
||||
public function afterScheduleAction(ArrayObject $args): void
|
||||
{
|
||||
// TODO: Implement afterSchedule() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $companyId
|
||||
* @param int $hubspotOwnerId
|
||||
*
|
||||
* @throws HubspotException
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
private function manageSaleStaffPerson(int $companyId, int $hubspotOwnerId): int
|
||||
{
|
||||
if ($companyId === 0 || $hubspotOwnerId === 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$addressResponse = $this->contactService->getHubspotOwner($hubspotOwnerId);
|
||||
|
||||
$address = $addressResponse->getJson();
|
||||
|
||||
if (empty($address)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$email = $address['email'];
|
||||
$sql = 'SELECT id FROM `adresse` WHERE `typ` != :type AND `email` = :email LIMIT 1';
|
||||
$addressId = $this->db->fetchValue($sql, ['type' => 'firma', 'email' => $email]);
|
||||
|
||||
$staffExists = $this->gateway->hubspotSaleStaffExists($companyId);
|
||||
if ($staffExists === true) {
|
||||
$sql = 'UPDATE `hubspot_contacts` SET `address_id` = :aid WHERE `hs_contact_id` = :id AND `data` = :company';
|
||||
$this->db->perform(
|
||||
$sql,
|
||||
[
|
||||
'id' => $hubspotOwnerId,
|
||||
'aid' => $addressId,
|
||||
'company' => (string)$companyId,
|
||||
]
|
||||
);
|
||||
} elseif ($addressId !== 0) {
|
||||
$this->db->perform(
|
||||
'INSERT INTO `hubspot_contacts` (`hs_contact_id`, `created_at`, `address_id`, `type`, `data`)
|
||||
VALUES (:id, NOW(), :aid, :type, :company)',
|
||||
['id' => $hubspotOwnerId, 'aid' => $addressId, 'type' => 'sale_staff', 'company' => (string)$companyId]
|
||||
);
|
||||
}
|
||||
|
||||
return $addressId;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,317 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\Hubspot\Scheduler;
|
||||
|
||||
use ArrayObject;
|
||||
use Exception;
|
||||
use Xentral\Components\Database\Database;
|
||||
use Xentral\Modules\Hubspot\Exception\HubspotDealGatewayNotFoundException;
|
||||
use Xentral\Modules\Hubspot\Exception\HubspotException;
|
||||
use Xentral\Modules\Hubspot\HubspotEventService;
|
||||
use Xentral\Modules\Hubspot\HubspotHttpResponseService as Response;
|
||||
use Xentral\Modules\Hubspot\HubspotConfigurationService;
|
||||
use Xentral\Modules\Hubspot\HubspotDealGateway;
|
||||
use Xentral\Modules\Hubspot\HubspotDealService;
|
||||
use Xentral\Modules\Hubspot\HubspotMetaService;
|
||||
use Xentral\Modules\Hubspot\HubspotContactGateway;
|
||||
use Xentral\Modules\SubscriptionCycle\Scheduler\TaskMutexServiceInterface;
|
||||
|
||||
final class HubspotPullDealsTask implements HubspotSchedulerTaskInterface
|
||||
{
|
||||
/** @var Database $db */
|
||||
private $db;
|
||||
|
||||
/** @var HubspotMetaService $meta */
|
||||
private $meta;
|
||||
|
||||
/** @var HubspotDealGateway $gateway */
|
||||
private $gateway;
|
||||
|
||||
/** @var HubspotDealService $dealService */
|
||||
private $dealService;
|
||||
|
||||
/** @var HubspotConfigurationService $configuration */
|
||||
private $configuration;
|
||||
|
||||
/** @var HubspotEventService $eventService */
|
||||
private $eventService;
|
||||
|
||||
/** @var HubspotContactGateway $contactGateway */
|
||||
private $contactGateway;
|
||||
|
||||
/** @var TaskMutexServiceInterface $taskMutexService */
|
||||
private $taskMutexService;
|
||||
|
||||
/**
|
||||
* @param HubspotDealService $dealService
|
||||
* @param Database $db
|
||||
* @param HubspotMetaService $metaService
|
||||
* @param HubspotDealGateway $gateway
|
||||
* @param HubspotConfigurationService $configuration
|
||||
* @param HubspotEventService $eventService
|
||||
* @param HubspotContactGateway $contactGateway
|
||||
* @param TaskMutexServiceInterface $taskMutexService
|
||||
*/
|
||||
public function __construct(
|
||||
HubspotDealService $dealService,
|
||||
Database $db,
|
||||
HubspotMetaService $metaService,
|
||||
HubspotDealGateway $gateway,
|
||||
HubspotConfigurationService $configuration,
|
||||
HubspotEventService $eventService,
|
||||
HubspotContactGateway $contactGateway,
|
||||
TaskMutexServiceInterface $taskMutexService
|
||||
) {
|
||||
$this->db = $db;
|
||||
$this->dealService = $dealService;
|
||||
$this->meta = $metaService;
|
||||
$this->gateway = $gateway;
|
||||
$this->configuration = $configuration;
|
||||
$this->eventService = $eventService;
|
||||
$this->contactGateway = $contactGateway;
|
||||
$this->taskMutexService = $taskMutexService;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $option
|
||||
*
|
||||
* @param null|string $type
|
||||
*
|
||||
* @param bool $recursiveMode
|
||||
*
|
||||
* @throws Exception
|
||||
* @return void
|
||||
*/
|
||||
public function execute($option = [], $type = null, $recursiveMode = false): void
|
||||
{
|
||||
if ($recursiveMode === false) {
|
||||
if ($this->taskMutexService->isTaskInstanceRunning('hubspot_pull_deals')) {
|
||||
return;
|
||||
}
|
||||
$this->taskMutexService->setMutex('hubspot_pull_deals');
|
||||
}
|
||||
$settings = $this->configuration->getSettings();
|
||||
if ($settings['hs_sync_deals'] !== true) {
|
||||
return;
|
||||
}
|
||||
|
||||
$type = $type ?? 'all_deals';
|
||||
|
||||
if ($type !== 'recently_updated_deals' && empty($recursiveMode) &&
|
||||
$this->db->fetchValue('SELECT COUNT(id) FROM hubspot_deals WHERE hidden=0') > 0) {
|
||||
$type = 'recently_created_deals';
|
||||
}
|
||||
|
||||
$ret = $this->pull($type, $option);
|
||||
|
||||
if (array_key_exists('has_more', $ret) && $ret['has_more'] === true) {
|
||||
$option = ['offset' => $ret['deal_offset']];
|
||||
$this->execute($option, $type, true);
|
||||
}
|
||||
|
||||
if ($ret['has_more'] === false && !in_array($type, ['all_deals', 'recently_updated_deals'])) {
|
||||
$this->execute([], 'recently_updated_deals');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function cleanup()
|
||||
{
|
||||
$this->taskMutexService->setMutex('hubspot_pull_deals', false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $type
|
||||
* @param array $options
|
||||
*
|
||||
* @throws Exception
|
||||
* @return array
|
||||
*/
|
||||
protected function pull($type = 'recently_created_deals', $options = [])
|
||||
{
|
||||
/** @var Response $response */
|
||||
$response = $this->dealService->pullDeals($type, $options);
|
||||
|
||||
if ($response->getStatusCode() === 200) {
|
||||
$data = $response->getJson();
|
||||
$offSet = array_key_exists('offset', $data) ? $data['offset'] : 0;
|
||||
$since = array_key_exists('since', $data) ? $data['since'] : 0;
|
||||
$hasMore = array_key_exists('hasMore', $data) ? $data['hasMore'] : false;
|
||||
|
||||
if (array_key_exists('deals', $data) || array_key_exists('results', $data)) {
|
||||
$deals = array_key_exists('deals', $data) ? $data['deals'] : $data['results'];
|
||||
|
||||
if (count($deals) > 0) {
|
||||
foreach ($deals as $deal) {
|
||||
$dealId = $deal['dealId'];
|
||||
$addressId = 0;
|
||||
|
||||
$associations = array_key_exists('associations', $deal) ? $deal['associations'] : [];
|
||||
|
||||
if (!empty($associations)) {
|
||||
$dealContactIds = $associations['associatedVids'];
|
||||
$companyIds = $associations['associatedCompanyIds'];
|
||||
if (!empty($companyIds)) {
|
||||
$dealContactIds = $companyIds;
|
||||
}
|
||||
if (!empty($dealContactIds)) {
|
||||
$dealContactId = $dealContactIds[0];
|
||||
$hsContact = $this->contactGateway->getMappingByHubspotId($dealContactId, null);
|
||||
if (!empty($hsContact)) {
|
||||
$addressId = $hsContact['address_id'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($deal['isDeleted'] === true) {
|
||||
// @todo delete from xentral
|
||||
continue;
|
||||
}
|
||||
if ($mapping = $this->gateway->getByHubspotId($dealId)) {
|
||||
// UPDATE
|
||||
if (($type === 'recently_updated_deals')) {
|
||||
$this->updateXTDeal($dealId, $mapping['wiedervorlage_id'], $addressId);
|
||||
//$updated++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($pipelineId = $this->addXTDeal($dealId, $addressId)) {
|
||||
$this->db->perform(
|
||||
'INSERT INTO `hubspot_deals` (`hs_deal_id`, `created_at`, `wiedervorlage_id`)
|
||||
VALUES (:id,NOW(), :pipelineId)',
|
||||
['id' => (int)$dealId, 'pipelineId' => $pipelineId]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($since === 0) {
|
||||
$since = time() * 1000;
|
||||
}
|
||||
|
||||
$this->meta->setName($type)->save(['offset' => $offSet, 'since' => $since]);
|
||||
|
||||
return ['deal_offset' => $offSet, 'has_more' => $hasMore];
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
public function beforeScheduleAction(ArrayObject $data)
|
||||
{
|
||||
if (empty($this->configuration->tryGetConfiguration(HubspotConfigurationService::HUBSPOT_SALT_CONF_NAME))) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
$leadsFields = $this->configuration->matchSelectedAddressFreeField();
|
||||
} catch (HubspotException $exception) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (empty($leadsFields)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ArrayObject $data
|
||||
*/
|
||||
public function afterScheduleAction(ArrayObject $data)
|
||||
{
|
||||
// TODO: Implement afterSchedule() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $dealId
|
||||
* @param int $addressId
|
||||
*
|
||||
* @throws HubspotException
|
||||
* @throws HubspotDealGatewayNotFoundException
|
||||
*
|
||||
* @throws Exception
|
||||
* @return int
|
||||
*/
|
||||
private function addXTDeal($dealId, $addressId = 0): int
|
||||
{
|
||||
if ($xtDeal = $this->configuration->formatDealByResponse($this->dealService->getDealById($dealId))) {
|
||||
$xtDeal['adr'] = $addressId;
|
||||
$this->db->perform(
|
||||
'INSERT INTO `wiedervorlage` (
|
||||
`bezeichnung`,
|
||||
`datum_angelegt`,
|
||||
`zeit_angelegt`,
|
||||
`datum_erinnerung`,
|
||||
`zeit_erinnerung`,
|
||||
`stages`,
|
||||
`adresse`
|
||||
)
|
||||
VALUES(:bezeichnung, :datum_angelegt, :zeit_angelegt, :datum_erinnerung, :zeit_erinnerung, :stages, :adr)',
|
||||
$xtDeal
|
||||
);
|
||||
|
||||
$latestId = $this->db->lastInsertId();
|
||||
|
||||
if ($data = $this->gateway->getMappingStageByResubmissionStageId($xtDeal['stages'])) {
|
||||
$viewId = $data['wiedervorlage_view_id'];
|
||||
// update
|
||||
$eventMsg = sprintf(
|
||||
'Neues Deal(<a href="/index.php?module=wiedervorlage&action=list&view=%d">%s</a>) vom Hubspot importiert.',
|
||||
$viewId,
|
||||
$xtDeal['bezeichnung']
|
||||
);
|
||||
|
||||
$this->eventService->add($eventMsg);
|
||||
}
|
||||
|
||||
return $latestId;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $dealId
|
||||
* @param int $wvId
|
||||
* @param int $addressId
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
private function updateXTDeal($dealId, $wvId, $addressId = 0)
|
||||
{
|
||||
if ($xtDeal = $this->configuration->formatDealByResponse($this->dealService->getDealById($dealId))) {
|
||||
$xtDeal['adr'] = $addressId;
|
||||
$affected = $this->db->fetchAffected(
|
||||
'UPDATE `wiedervorlage`
|
||||
SET `bezeichnung` = :bezeichnung,
|
||||
`datum_angelegt` = :datum_angelegt,
|
||||
`zeit_angelegt` = :zeit_angelegt,
|
||||
`datum_erinnerung` = :datum_erinnerung,
|
||||
`zeit_erinnerung` = :zeit_erinnerung,
|
||||
`stages` = :stages,
|
||||
`adresse` = :adr
|
||||
WHERE `id` =' . $wvId,
|
||||
$xtDeal
|
||||
);
|
||||
|
||||
if ($affected > 0) {
|
||||
$data = $this->gateway->getMappingStageByResubmissionStageId($xtDeal['stages']);
|
||||
if (empty($data)) {
|
||||
return;
|
||||
}
|
||||
$viewId = $data['wiedervorlage_view_id'];
|
||||
// update
|
||||
$eventMsg = sprintf(
|
||||
'Geändertes Deal(<a href="/index.php?module=wiedervorlage&action=list&view=%d">%s</a>) vom Hubspot importiert.',
|
||||
$viewId,
|
||||
$xtDeal['bezeichnung']
|
||||
);
|
||||
$this->eventService->add($eventMsg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,289 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\Hubspot\Scheduler;
|
||||
|
||||
use ArrayObject;
|
||||
use Xentral\Components\Database\Database;
|
||||
use Xentral\Modules\Hubspot\Exception\HubspotConfigurationServiceException;
|
||||
use Xentral\Modules\Hubspot\Exception\HubspotException;
|
||||
use Xentral\Modules\Hubspot\Exception\MetaException;
|
||||
use Xentral\Modules\Hubspot\HubspotConfigurationService;
|
||||
use Xentral\Modules\Hubspot\HubspotContactGateway;
|
||||
use Xentral\Modules\Hubspot\HubspotEngagementService;
|
||||
use Xentral\Modules\Hubspot\HubspotEventService;
|
||||
use Xentral\Modules\Hubspot\HubspotMetaService;
|
||||
use Xentral\Modules\SubscriptionCycle\Scheduler\TaskMutexServiceInterface;
|
||||
|
||||
final class HubspotPullEngagementsTask implements HubspotSchedulerTaskInterface
|
||||
{
|
||||
|
||||
/** @var int[] $itemsCount */
|
||||
private $itemsCount = ['count' => 100];
|
||||
|
||||
/** @var Database $db */
|
||||
private $db;
|
||||
|
||||
/** @var HubspotEngagementService $engagementsService */
|
||||
private $engagementsService;
|
||||
|
||||
/** @var HubspotMetaService $meta */
|
||||
private $meta;
|
||||
|
||||
/** @var HubspotConfigurationService $configuration */
|
||||
private $configuration;
|
||||
|
||||
/** @var HubspotEventService $event */
|
||||
private $event;
|
||||
|
||||
/** @var HubspotContactGateway $contactGateway */
|
||||
private $contactGateway;
|
||||
|
||||
/** @var TaskMutexServiceInterface $taskMutexService */
|
||||
private $taskMutexService;
|
||||
|
||||
/**
|
||||
* @param Database $db
|
||||
* @param HubspotEngagementService $engagementService
|
||||
* @param HubspotMetaService $metaService
|
||||
* @param HubspotConfigurationService $configuration
|
||||
* @param HubspotEventService $eventService
|
||||
* @param HubspotContactGateway $contactGateway
|
||||
* @param TaskMutexServiceInterface $taskMutexService
|
||||
*/
|
||||
public function __construct(
|
||||
Database $db,
|
||||
HubspotEngagementService $engagementService,
|
||||
HubspotMetaService $metaService,
|
||||
HubspotConfigurationService $configuration,
|
||||
HubspotEventService $eventService,
|
||||
HubspotContactGateway $contactGateway,
|
||||
TaskMutexServiceInterface $taskMutexService
|
||||
) {
|
||||
$this->db = $db;
|
||||
$this->engagementsService = $engagementService;
|
||||
$this->configuration = $configuration;
|
||||
$this->meta = $metaService;
|
||||
$this->event = $eventService;
|
||||
$this->contactGateway = $contactGateway;
|
||||
$this->taskMutexService = $taskMutexService;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws HubspotException
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function execute(): void
|
||||
{
|
||||
if ($this->taskMutexService->isTaskInstanceRunning('hubspot_pull_engagements')) {
|
||||
return;
|
||||
}
|
||||
$this->taskMutexService->setMutex('hubspot_pull_engagements');
|
||||
|
||||
try {
|
||||
$settings = $this->configuration->getSettings();
|
||||
} catch (HubspotConfigurationServiceException $e) {
|
||||
return;
|
||||
}
|
||||
if (empty($settings['hs_sync_engagements'])) {
|
||||
return;
|
||||
}
|
||||
$this->recursiveExecute();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $option
|
||||
*
|
||||
* @throws HubspotException
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function recursiveExecute(array $option = []): void
|
||||
{
|
||||
$remainingData = $this->pull($option);
|
||||
|
||||
if (!empty($remainingData['has_more'])) {
|
||||
unset($remainingData['has_more']);
|
||||
$this->recursiveExecute($remainingData);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $options
|
||||
*
|
||||
* @throws HubspotException
|
||||
*
|
||||
* @return array|null
|
||||
*/
|
||||
private function pull(array $options = []): ?array
|
||||
{
|
||||
$options = array_merge($options, $this->itemsCount);
|
||||
|
||||
$metaInfo = $this->meta->setName('recent_engagements')->get();
|
||||
$requestData = [];
|
||||
if (array_key_exists('since', $metaInfo)) {
|
||||
$requestData['since'] = $metaInfo['since'];
|
||||
}
|
||||
if (array_key_exists('offset', $metaInfo)) {
|
||||
$requestData['offset'] = $metaInfo['offset'];
|
||||
}
|
||||
$options = array_merge($options, $requestData);
|
||||
$response = $this->engagementsService->getRecentEngagements($options);
|
||||
|
||||
if ($response->getStatusCode() !== 200) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$data = $response->getJson();
|
||||
|
||||
$offSet = array_key_exists('offset', $data) ? $data['offset'] : 0;
|
||||
$hasMore = array_key_exists('hasMore', $data) ? $data['hasMore'] : false;
|
||||
$total = array_key_exists('total', $data) ? $data['total'] : 0;
|
||||
$since = array_key_exists('since', $data) ? $data['since'] : time() * 1000;
|
||||
|
||||
if ($total === 0 || !array_key_exists('results', $data)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$engagements = $data['results'];
|
||||
|
||||
foreach ($engagements as $engagement) {
|
||||
$engagementData = $engagement['engagement'];
|
||||
// ONLY TYPE NOTE IS CURRENTLY ALLOWED
|
||||
if ($engagementData['type'] !== 'NOTE') {
|
||||
continue;
|
||||
}
|
||||
$engagementId = $engagementData['id'];
|
||||
$engagementAssociations = $engagement['associations'];
|
||||
$metadata = $engagement['metadata'];
|
||||
$body = $metadata['body'];
|
||||
$companyIds = null;
|
||||
$contactIds = null;
|
||||
if ($this->engagementExists($engagementId)) {
|
||||
continue;
|
||||
}
|
||||
foreach ($engagementAssociations as $intended => $values) {
|
||||
if (!is_string($intended)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($intended === 'companyIds') {
|
||||
$companyIds = $values;
|
||||
}
|
||||
|
||||
if ($intended === 'contactIds') {
|
||||
$contactIds = $values;
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($companyIds) && empty($contactIds)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$intendedIds = array_merge($companyIds, $contactIds);
|
||||
foreach ($intendedIds as $intendedId) {
|
||||
$noteId = $this->addNote($intendedId, $body);
|
||||
if (empty($noteId)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$mapping = $this->contactGateway->getMappingByHubspotId($intendedId, null);
|
||||
if (empty($mapping)) {
|
||||
continue;
|
||||
}
|
||||
$addressId = $mapping['address_id'];
|
||||
$this->db->perform(
|
||||
'INSERT INTO `hubspot_contacts` (`hs_contact_id`, `created_at`, `address_id`, `type`)
|
||||
VALUES (:id, NOW(), :aid, :type)',
|
||||
['id' => $engagementId, 'aid' => $noteId, 'type' => 'note']
|
||||
);
|
||||
$eventItem = 'Adresse';
|
||||
|
||||
$eventMsg = sprintf(
|
||||
'Neue Notiz vom Hubspot hinzugefügt ins Xentral für (<a href="/index.php?module=adresse&action=edit&id=%d">%s</a>) importiert.',
|
||||
$addressId,
|
||||
$eventItem
|
||||
);
|
||||
$this->event->add($eventMsg);
|
||||
}
|
||||
}
|
||||
|
||||
$remainingData = ['offset' => $offSet, 'since' => $since];
|
||||
|
||||
try {
|
||||
$this->meta->setName('recent_engagements')->save($remainingData);
|
||||
} catch (MetaException $e) {
|
||||
$this->event->add($e->getMessage());
|
||||
}
|
||||
|
||||
$remainingData['has_more'] = $hasMore;
|
||||
|
||||
return $remainingData;
|
||||
}
|
||||
|
||||
public function cleanup()
|
||||
{
|
||||
$this->taskMutexService->setMutex('hubspot_pull_engagements', false);
|
||||
}
|
||||
|
||||
public function beforeScheduleAction(ArrayObject $args)
|
||||
{
|
||||
}
|
||||
|
||||
public function afterScheduleAction(ArrayObject $args)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $hubspotContactId
|
||||
* @param string $body
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
private function addNote(int $hubspotContactId, string $body): int
|
||||
{
|
||||
|
||||
$mapping = $this->contactGateway->getMappingByHubspotId($hubspotContactId, null);
|
||||
if (empty($mapping)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$sql = 'INSERT INTO `dokumente` (
|
||||
`adresse_to`,
|
||||
`adresse_from`,
|
||||
`typ`,
|
||||
`betreff`,
|
||||
`content`,
|
||||
`datum`,
|
||||
`uhrzeit`,
|
||||
`created`,
|
||||
`bearbeiter`)
|
||||
VALUES (:address, 1, :type, :object, :body, :date, :time, NOW(), :editor)';
|
||||
$this->db->perform(
|
||||
$sql,
|
||||
[
|
||||
'address' => $mapping['address_id'],
|
||||
'type' => 'notiz',
|
||||
'object' => 'Hubspot note',
|
||||
'body' => $body,
|
||||
'date' => date('Y-m-d'),
|
||||
'time' => date('H:i:s'),
|
||||
'editor' => 'HubspotModule',
|
||||
]
|
||||
);
|
||||
|
||||
return $this->db->lastInsertId();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $engagementId
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function engagementExists(int $engagementId) : bool
|
||||
{
|
||||
return $this->contactGateway->hubspotContactExists($engagementId, ['note']);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\Hubspot\Scheduler;
|
||||
|
||||
use ArrayObject;
|
||||
|
||||
interface HubspotSchedulerTaskInterface
|
||||
{
|
||||
public function execute();
|
||||
|
||||
public function cleanup();
|
||||
|
||||
public function beforeScheduleAction(ArrayObject $args);
|
||||
|
||||
public function afterScheduleAction(ArrayObject $args);
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\Hubspot\Validators;
|
||||
|
||||
final class ContactPropertyValidator implements ValidatorInterface
|
||||
{
|
||||
|
||||
/** @var string */
|
||||
private $rules;
|
||||
|
||||
public function __construct($rules = 'default')
|
||||
{
|
||||
$this->rules = $rules;
|
||||
}
|
||||
|
||||
public function isValid($data = [])
|
||||
{
|
||||
// TODO: Implement isValid() method.
|
||||
}
|
||||
|
||||
public function validatorRuleDefault()
|
||||
{
|
||||
// TODO: Implement validatorRuleDefault() method.
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\Hubspot\Validators;
|
||||
|
||||
use Xentral\Modules\Hubspot\Exception\HubspotException;
|
||||
|
||||
final class ContactValidator implements ValidatorInterface
|
||||
{
|
||||
|
||||
/** @var string */
|
||||
private $rules;
|
||||
private $data;
|
||||
|
||||
public function __construct($rules = 'default')
|
||||
{
|
||||
$this->rules = $rules;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function validatorRuleDefault()
|
||||
{
|
||||
return [
|
||||
'email' => [
|
||||
'rule' => static function ($data) {
|
||||
return !empty($data['email']) && is_string($data['email']);
|
||||
},
|
||||
'required' => false,
|
||||
'message' => sprintf('%s should be a non empty String', 'Email'),
|
||||
],
|
||||
'firstname' => [
|
||||
'rule' => static function ($data) {
|
||||
return !empty($data['firstname']) && is_string($data['firstname']);
|
||||
},
|
||||
'required' => false,
|
||||
'message' => sprintf('%s should be a non empty String', 'First name'),
|
||||
],
|
||||
'lastname' => [
|
||||
'rule' => static function ($data) {
|
||||
return !empty($data['lastname']) && is_string($data['lastname']);
|
||||
},
|
||||
'required' => false,
|
||||
'message' => sprintf('%s should be a non empty String', 'Last name'),
|
||||
],
|
||||
|
||||
'website' => [
|
||||
'rule' => static function ($data) {
|
||||
return !empty($data['website']) && is_string($data['website']);
|
||||
},
|
||||
'required' => false,
|
||||
'message' => sprintf('%s should be a non empty String', 'Website'),
|
||||
],
|
||||
|
||||
'company' => [
|
||||
'rule' => static function ($data) {
|
||||
return !empty($data['company']) && is_string($data['company']);
|
||||
},
|
||||
'required' => false,
|
||||
'message' => sprintf('%s should be a non empty String', 'company'),
|
||||
],
|
||||
|
||||
'phone' => [
|
||||
'rule' => static function ($data) {
|
||||
return !empty($data['phone']) && is_string($data['phone']);
|
||||
},
|
||||
'required' => false,
|
||||
'message' => sprintf('%s should be a non empty String', 'phone'),
|
||||
],
|
||||
|
||||
'address' => [
|
||||
'rule' => static function ($data) {
|
||||
return !empty($data['address']) && is_string($data['address']);
|
||||
},
|
||||
'required' => false,
|
||||
'message' => sprintf('%s should be a non empty String', 'Address'),
|
||||
],
|
||||
|
||||
'city' => [
|
||||
'rule' => static function ($data) {
|
||||
return !empty($data['city']) && is_string($data['city']);
|
||||
},
|
||||
'required' => false,
|
||||
'message' => sprintf('%s should be a non empty String', 'city'),
|
||||
],
|
||||
'state' => [
|
||||
'rule' => static function ($data) {
|
||||
return !empty($data['state']) && is_string($data['state']);
|
||||
},
|
||||
'required' => false,
|
||||
'message' => sprintf('%s should be a non empty String', 'state'),
|
||||
],
|
||||
'zip' => [
|
||||
'rule' => static function ($data) {
|
||||
return !empty($data['zip']) && is_string($data['zip']);
|
||||
},
|
||||
'required' => false,
|
||||
'message' => sprintf('%s should be a non empty String', 'zip'),
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isValid($data = [])
|
||||
{
|
||||
$this->data = $data;
|
||||
$validatorMethod = 'validatorRule' . ucfirst($this->rules);
|
||||
if (!method_exists($this, $validatorMethod)) {
|
||||
throw new HubspotException(sprintf('Validator method %s is missing', $validatorMethod));
|
||||
}
|
||||
|
||||
$rules = $this->{$validatorMethod}();
|
||||
foreach ($rules as $field => $rule) {
|
||||
if (array_key_exists('rule', $rule)) {
|
||||
$validation = call_user_func($rule['rule'], $this->data);
|
||||
if (!$validation && (!empty($this->data[$field]) || !empty($rule['required']))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getData()
|
||||
{
|
||||
return array_filter($this->data, static function ($value) {
|
||||
return $value !== null && trim($value) !== '';
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\Hubspot\Validators;
|
||||
|
||||
use Xentral\Modules\Hubspot\Exception\HubspotException;
|
||||
|
||||
final class DealValidator implements ValidatorInterface
|
||||
{
|
||||
|
||||
/** @var string */
|
||||
private $rules;
|
||||
private $data;
|
||||
|
||||
public function __construct($rules = 'default')
|
||||
{
|
||||
$this->rules = $rules;
|
||||
}
|
||||
|
||||
|
||||
public function isValid($data = [])
|
||||
{
|
||||
$validatorMethod = 'validatorRule' . ucfirst($this->rules);
|
||||
if (!method_exists($this, $validatorMethod)) {
|
||||
throw new HubspotException(sprintf('Validator method %s is missing', $validatorMethod));
|
||||
}
|
||||
$this->data = $data;
|
||||
$rules = $this->{$validatorMethod}();
|
||||
foreach ($rules as $field => $rule) {
|
||||
if (array_key_exists('rule', $rule)) {
|
||||
$validation = call_user_func($rule['rule'], $data);
|
||||
if (!$validation && (!empty($this->data[$field]) || !empty($rule['required']))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function validatorRuleDefault()
|
||||
{
|
||||
return [
|
||||
'dealname' => [
|
||||
'rule' => static function ($data) {
|
||||
return !empty($data['dealname']) && is_string($data['dealname']);
|
||||
},
|
||||
'required' => true,
|
||||
'message' => sprintf('%s should be a non empty String', 'name'),
|
||||
],
|
||||
'dealstage' => [
|
||||
'rule' => static function ($data) {
|
||||
return !empty($data['dealstage']) && is_string($data['dealstage']);
|
||||
},
|
||||
'required' => false,
|
||||
'message' => sprintf('%s should be a non empty String', 'Deal stage'),
|
||||
],
|
||||
'pipeline' => [
|
||||
'rule' => static function ($data) {
|
||||
return !empty($data['pipeline']) && is_string($data['pipeline']);
|
||||
},
|
||||
'required' => false,
|
||||
'message' => sprintf('%s should be a non empty String', 'Pipeline'),
|
||||
],
|
||||
|
||||
'hubspot_owner_id' => [
|
||||
'rule' => static function ($data) {
|
||||
return !empty($data['hubspot_owner_id']) && is_numeric($data['hubspot_owner_id']);
|
||||
},
|
||||
'required' => false,
|
||||
'message' => sprintf('%s should be a non empty String', 'hubspot_owner_id'),
|
||||
],
|
||||
|
||||
'closedate' => [
|
||||
'rule' => static function ($data) {
|
||||
return !empty($data['closedate']) && is_numeric($data['closedate']);
|
||||
},
|
||||
'required' => false,
|
||||
'message' => sprintf('%s should be a non empty String', 'closedate'),
|
||||
],
|
||||
|
||||
'dealtype' => [
|
||||
'rule' => static function ($data) {
|
||||
return !empty($data['dealtype']) && is_string($data['dealtype']);
|
||||
},
|
||||
'required' => false,
|
||||
'message' => sprintf('%s should be a non empty String', 'dealtype'),
|
||||
],
|
||||
|
||||
'amount' => [
|
||||
'rule' => static function ($data) {
|
||||
return !empty($data['amount']) && is_numeric($data['amount']);
|
||||
},
|
||||
'required' => false,
|
||||
'message' => sprintf('%s should be a non empty String', 'amount'),
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
public function getData()
|
||||
{
|
||||
return array_filter($this->data, static function ($value) {
|
||||
return $value !== null && trim($value) !== '';
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\Hubspot\Validators;
|
||||
|
||||
interface ValidatorInterface
|
||||
{
|
||||
public function isValid($data=[]);
|
||||
public function validatorRuleDefault();
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
.hs-visible{
|
||||
/*display:block;*/
|
||||
visibility: visible;
|
||||
}
|
||||
.hs-invisible{
|
||||
visibility: hidden;
|
||||
display: none;
|
||||
}
|
||||
#hs-add-more-field {
|
||||
color: #367FA9;
|
||||
cursor: pointer;
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
var HubSpotModule = function ($) {
|
||||
'use strict';
|
||||
|
||||
var me = {
|
||||
|
||||
isInitialized: false,
|
||||
|
||||
storage: {},
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
init: function () {
|
||||
if (me.isInitialized === true) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
me.registerEvents();
|
||||
|
||||
me.isInitialized = true;
|
||||
},
|
||||
|
||||
registerEvents: function () {
|
||||
$('#sync_hs_xt').on('click', function (event) {
|
||||
me.syncAccount();
|
||||
event.preventDefault();
|
||||
});
|
||||
|
||||
$('#hs-add-more-field ').on('click', function () {
|
||||
me.addMoreCustomField();;
|
||||
});
|
||||
|
||||
$('#no-matching').on('click', function (event) {
|
||||
$(this).prop('checked', true);
|
||||
$('#do-matching').prop('checked', false);
|
||||
me.hideMatchingSetting();
|
||||
});
|
||||
|
||||
$('#do-matching').on('click', function (event) {
|
||||
$(this).prop('checked', true);
|
||||
$('#no-matching').prop('checked', false);
|
||||
me.showMatchingSetting();
|
||||
});
|
||||
},
|
||||
|
||||
showMatchingSetting: function () {
|
||||
$('.deal-system').removeClass('hs-invisible').find('select').prop('disabled', false);
|
||||
},
|
||||
|
||||
hideMatchingSetting: function () {
|
||||
$('.deal-system').addClass('hs-invisible').find('select').prop('disabled', true);
|
||||
},
|
||||
|
||||
/**
|
||||
* @return {void}
|
||||
*/
|
||||
addApiKey: function () {
|
||||
if (me.isInitialized === false) {
|
||||
me.init();
|
||||
}
|
||||
|
||||
me.resetAdd();
|
||||
me.storage.$createItemDialog.dialog('open');
|
||||
},
|
||||
|
||||
/**
|
||||
* @return {void}
|
||||
*/
|
||||
syncAccount: function () {
|
||||
var $form = $('#hs-configurator-form');
|
||||
$form.action = 'index.php?module=hubspot&action=apikey';
|
||||
$form.submit();
|
||||
},
|
||||
addMoreCustomField: function () {
|
||||
var $tableTr = $('tr[id^="field"]:last');
|
||||
var num = parseInt($tableTr.prop('id').match(/\d+/g), 10) + 1;
|
||||
var $clone = $tableTr.clone().prop('id', 'field' + num);
|
||||
$tableTr.after($clone.html(
|
||||
'<td width="150">Eigenschaft ' + num + ' :</td>' +
|
||||
'<td><input type="text" name="custom_field[]" class="fd_custom_field" placeholder=\"Feld name\" id="field' + num + '" value=""></td>'));
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
return {
|
||||
init: me.init,
|
||||
addApiKey: me.addApiKey
|
||||
};
|
||||
|
||||
}(jQuery);
|
||||
|
||||
$(function () {
|
||||
if ($('#sync_hs_xt').length > 0) {
|
||||
HubSpotModule.init();
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user