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 (%s) 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 (%s) 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; } }