1 | <?php |
||
2 | |||
3 | /* |
||
4 | * @copyright 2014 Mautic Contributors. All rights reserved |
||
5 | * @author Mautic |
||
6 | * |
||
7 | * @link http://mautic.org |
||
8 | * |
||
9 | * @license GNU/GPLv3 http://www.gnu.org/licenses/gpl-3.0.html |
||
10 | */ |
||
11 | |||
12 | namespace MauticPlugin\MauticCrmBundle\Integration; |
||
13 | |||
14 | use Doctrine\ORM\EntityManager; |
||
15 | use Mautic\CoreBundle\Form\Type\ButtonGroupType; |
||
16 | use Mautic\CoreBundle\Helper\CacheStorageHelper; |
||
17 | use Mautic\CoreBundle\Helper\EncryptionHelper; |
||
18 | use Mautic\CoreBundle\Helper\PathsHelper; |
||
19 | use Mautic\CoreBundle\Model\NotificationModel; |
||
20 | use Mautic\LeadBundle\Entity\Company; |
||
21 | use Mautic\LeadBundle\Entity\Lead; |
||
22 | use Mautic\LeadBundle\Model\CompanyModel; |
||
23 | use Mautic\LeadBundle\Model\DoNotContact; |
||
24 | use Mautic\LeadBundle\Model\FieldModel; |
||
25 | use Mautic\LeadBundle\Model\LeadModel; |
||
26 | use Mautic\PluginBundle\Entity\IntegrationEntity; |
||
27 | use Mautic\PluginBundle\Entity\IntegrationEntityRepository; |
||
28 | use Mautic\PluginBundle\Exception\ApiErrorException; |
||
29 | use Mautic\PluginBundle\Model\IntegrationEntityModel; |
||
30 | use Mautic\UserBundle\Model\UserModel; |
||
31 | use Monolog\Logger; |
||
32 | use Symfony\Component\EventDispatcher\EventDispatcherInterface; |
||
33 | use Symfony\Component\Form\Extension\Core\Type\ChoiceType; |
||
34 | use Symfony\Component\Form\FormBuilder; |
||
35 | use Symfony\Component\HttpFoundation\RequestStack; |
||
36 | use Symfony\Component\HttpFoundation\Session\Session; |
||
37 | use Symfony\Component\Routing\Generator\UrlGeneratorInterface; |
||
38 | use Symfony\Component\Routing\Router; |
||
39 | use Symfony\Component\Translation\TranslatorInterface; |
||
40 | use Symfony\Component\Validator\Constraints\NotBlank; |
||
41 | |||
42 | class SugarcrmIntegration extends CrmAbstractIntegration |
||
43 | { |
||
44 | private $objects = [ |
||
45 | 'Leads', |
||
46 | 'Contacts', |
||
47 | 'Accounts', |
||
48 | ]; |
||
49 | |||
50 | private $sugarDncKeys = ['email_opt_out', 'invalid_email']; |
||
51 | private $authorizationError; |
||
52 | private $userModel; |
||
53 | |||
54 | /** |
||
55 | * @var DoNotContact |
||
56 | */ |
||
57 | protected $doNotContactModel; |
||
58 | |||
59 | public function __construct( |
||
60 | EventDispatcherInterface $eventDispatcher, |
||
61 | CacheStorageHelper $cacheStorageHelper, |
||
62 | EntityManager $entityManager, |
||
63 | Session $session, |
||
64 | RequestStack $requestStack, |
||
65 | Router $router, |
||
66 | TranslatorInterface $translator, |
||
67 | Logger $logger, |
||
68 | EncryptionHelper $encryptionHelper, |
||
69 | LeadModel $leadModel, |
||
70 | CompanyModel $companyModel, |
||
71 | PathsHelper $pathsHelper, |
||
72 | NotificationModel $notificationModel, |
||
73 | FieldModel $fieldModel, |
||
74 | IntegrationEntityModel $integrationEntityModel, |
||
75 | DoNotContact $doNotContactModel, |
||
76 | UserModel $userModel |
||
77 | ) { |
||
78 | $this->doNotContactModel = $doNotContactModel; |
||
79 | $this->userModel = $userModel; |
||
80 | |||
81 | parent::__construct( |
||
82 | $eventDispatcher, |
||
83 | $cacheStorageHelper, |
||
84 | $entityManager, |
||
85 | $session, |
||
86 | $requestStack, |
||
87 | $router, |
||
88 | $translator, |
||
89 | $logger, |
||
90 | $encryptionHelper, |
||
91 | $leadModel, |
||
92 | $companyModel, |
||
93 | $pathsHelper, |
||
94 | $notificationModel, |
||
95 | $fieldModel, |
||
96 | $integrationEntityModel, |
||
97 | $doNotContactModel |
||
98 | ); |
||
99 | } |
||
100 | |||
101 | /** |
||
102 | * Returns the name of the social integration that must match the name of the file. |
||
103 | * |
||
104 | * @return string |
||
105 | */ |
||
106 | public function getName() |
||
107 | { |
||
108 | return 'Sugarcrm'; |
||
109 | } |
||
110 | |||
111 | /** |
||
112 | * @return array |
||
113 | */ |
||
114 | public function getSupportedFeatures() |
||
115 | { |
||
116 | //Version 6.x supports all features |
||
117 | if (isset($this->keys['version']) && '6' == $this->keys['version']) { |
||
118 | return ['push_lead', 'get_leads', 'push_leads']; |
||
119 | } |
||
120 | //Only push_lead is currently supported for version 7 |
||
121 | return ['push_lead', 'get_leads', 'push_leads']; |
||
122 | } |
||
123 | |||
124 | /** |
||
125 | * Get the array key for clientId. |
||
126 | * |
||
127 | * @return string |
||
128 | */ |
||
129 | public function getClientIdKey() |
||
130 | { |
||
131 | return 'client_id'; |
||
132 | } |
||
133 | |||
134 | /** |
||
135 | * Get the array key for client secret. |
||
136 | * |
||
137 | * @return string |
||
138 | */ |
||
139 | public function getClientSecretKey() |
||
140 | { |
||
141 | return 'client_secret'; |
||
142 | } |
||
143 | |||
144 | /** |
||
145 | * {@inheritdoc} |
||
146 | * |
||
147 | * @return array |
||
148 | */ |
||
149 | public function getSecretKeys() |
||
150 | { |
||
151 | return [ |
||
152 | 'client_secret', |
||
153 | 'password', |
||
154 | ]; |
||
155 | } |
||
156 | |||
157 | /** |
||
158 | * Get the array key for the auth token. |
||
159 | * |
||
160 | * @return string |
||
161 | */ |
||
162 | public function getAuthTokenKey() |
||
163 | { |
||
164 | return (isset($this->keys['version']) && '6' == $this->keys['version']) ? 'id' : 'access_token'; |
||
165 | } |
||
166 | |||
167 | /** |
||
168 | * SugarCRM 7 refresh tokens. |
||
169 | */ |
||
170 | public function getRefreshTokenKeys() |
||
171 | { |
||
172 | return [ |
||
173 | 'refresh_token', |
||
174 | 'expires', |
||
175 | ]; |
||
176 | } |
||
177 | |||
178 | /** |
||
179 | * {@inheritdoc} |
||
180 | * |
||
181 | * @return string |
||
182 | */ |
||
183 | public function getAccessTokenUrl() |
||
184 | { |
||
185 | $apiUrl = ('6' == $this->keys['version']) ? 'service/v4_1/rest.php' : 'rest/v10/oauth2/token'; |
||
186 | |||
187 | return sprintf('%s/%s', $this->keys['sugarcrm_url'], $apiUrl); |
||
188 | } |
||
189 | |||
190 | /** |
||
191 | * {@inheritdoc} |
||
192 | * |
||
193 | * @return string |
||
194 | */ |
||
195 | public function getAuthLoginUrl() |
||
196 | { |
||
197 | return $this->router->generate('mautic_integration_auth_callback', ['integration' => $this->getName()]); |
||
198 | } |
||
199 | |||
200 | /** |
||
201 | * Retrieves and stores tokens returned from oAuthLogin. |
||
202 | * |
||
203 | * @param array $settings |
||
204 | * @param array $parameters |
||
205 | * |
||
206 | * @return array |
||
207 | */ |
||
208 | public function authCallback($settings = [], $parameters = []) |
||
209 | { |
||
210 | if (isset($this->keys['version']) && '6' == $this->keys['version']) { |
||
211 | $success = $this->isAuthorized(); |
||
212 | if (!$success) { |
||
213 | return $this->authorizationError; |
||
214 | } else { |
||
215 | return false; |
||
216 | } |
||
217 | } else { |
||
218 | $settings = [ |
||
219 | 'grant_type' => 'password', |
||
220 | 'ignore_redirecturi' => true, |
||
221 | ]; |
||
222 | $parameters = [ |
||
223 | 'username' => $this->keys['username'], |
||
224 | 'password' => $this->keys['password'], |
||
225 | 'platform' => 'base', |
||
226 | ]; |
||
227 | |||
228 | return parent::authCallback($settings, $parameters); |
||
229 | } |
||
230 | } |
||
231 | |||
232 | /** |
||
233 | * {@inheritdoc} |
||
234 | * |
||
235 | * @return array |
||
236 | */ |
||
237 | public function getRequiredKeyFields() |
||
238 | { |
||
239 | return [ |
||
240 | 'sugarcrm_url' => 'mautic.sugarcrm.form.url', |
||
241 | 'client_id' => 'mautic.sugarcrm.form.clientkey', |
||
242 | 'client_secret' => 'mautic.sugarcrm.form.clientsecret', |
||
243 | 'username' => 'mautic.sugarcrm.form.username', |
||
244 | 'password' => 'mautic.sugarcrm.form.password', |
||
245 | ]; |
||
246 | } |
||
247 | |||
248 | /** |
||
249 | * Get available company fields for choices in the config UI. |
||
250 | * |
||
251 | * @param array $settings |
||
252 | * |
||
253 | * @return array |
||
254 | */ |
||
255 | public function getFormCompanyFields($settings = []) |
||
256 | { |
||
257 | return $this->getFormFieldsByObject('company', $settings); |
||
258 | } |
||
259 | |||
260 | /** |
||
261 | * Get available fields for choices in the config UI. |
||
262 | * |
||
263 | * @param array $settings |
||
264 | * |
||
265 | * @return array |
||
266 | */ |
||
267 | public function getFormLeadFields($settings = []) |
||
268 | { |
||
269 | if (!$this->isAuthorized()) { |
||
270 | return []; |
||
271 | } |
||
272 | |||
273 | if (isset($settings['feature_settings']['objects'])) { |
||
274 | // combine keys with values |
||
275 | $settings['feature_settings']['objects'] = array_combine( |
||
276 | array_values($settings['feature_settings']['objects']), |
||
277 | $settings['feature_settings']['objects'] |
||
278 | ); |
||
279 | } |
||
280 | |||
281 | // unset company object |
||
282 | if (isset($settings['feature_settings']['objects']['company'])) { |
||
283 | unset($settings['feature_settings']['objects']['company']); |
||
284 | } |
||
285 | |||
286 | if (empty($settings['feature_settings']['objects'])) { |
||
287 | // BC force add Leads and Contacts from Integration |
||
288 | $settings['feature_settings']['objects']['Leads'] = 'Leads'; |
||
289 | $settings['feature_settings']['objects']['Contacts'] = 'Contacts'; |
||
290 | } |
||
291 | |||
292 | $fields = []; |
||
293 | // merge all arrays from level 1 |
||
294 | $fieldsromObjects = $this->getAvailableLeadFields($settings); |
||
295 | foreach ($fieldsromObjects as $fieldsFromObject) { |
||
296 | $fields = array_merge($fields, $fieldsFromObject); |
||
297 | } |
||
298 | |||
299 | return $fields; |
||
300 | } |
||
301 | |||
302 | /** |
||
303 | * @param array $settings |
||
304 | * |
||
305 | * @return array |
||
306 | * |
||
307 | * @throws \Exception |
||
308 | */ |
||
309 | public function getAvailableLeadFields($settings = []) |
||
310 | { |
||
311 | $sugarFields = []; |
||
312 | $silenceExceptions = (isset($settings['silence_exceptions'])) ? $settings['silence_exceptions'] : true; |
||
313 | $sugarObjects = []; |
||
314 | |||
315 | if (!empty($settings['feature_settings']['objects'])) { |
||
316 | $sugarObjects = $settings['feature_settings']['objects']; |
||
317 | } else { |
||
318 | $sugarObjects['Leads'] = 'Leads'; |
||
319 | $sugarObjects['Contacts'] = 'Contacts'; |
||
320 | $settings['feature_settings']['objects'] = $sugarObjects; |
||
321 | } |
||
322 | |||
323 | $isRequired = function (array $field, $object) { |
||
324 | switch (true) { |
||
325 | case 'Leads' === $object && ('webtolead_email1' === $field['name'] || 'email1' === $field['name']): |
||
326 | case 'Contacts' === $object && 'email1' === $field['name']: |
||
327 | case 'id' !== $field['name'] && !empty($field['required']): |
||
328 | return true; |
||
329 | default: |
||
330 | return false; |
||
331 | } |
||
332 | }; |
||
333 | |||
334 | try { |
||
335 | if (!empty($sugarObjects) and is_array($sugarObjects)) { |
||
336 | foreach ($sugarObjects as $sObject) { |
||
337 | if ('Accounts' === $sObject) { |
||
338 | // Match Sugar object to Mautic's |
||
339 | $sObject = 'company'; |
||
340 | } |
||
341 | $sObject = trim($sObject); |
||
342 | if ($this->isAuthorized()) { |
||
343 | // Check the cache first |
||
344 | $settings['cache_suffix'] = $cacheSuffix = '.'.$sObject; |
||
345 | if ($fields = parent::getAvailableLeadFields($settings)) { |
||
346 | if (('company' === $sObject && isset($fields['id'])) || isset($fields['id__'.$sObject])) { |
||
347 | $sugarFields[$sObject] = $fields; |
||
348 | continue; |
||
349 | } |
||
350 | } |
||
351 | if (!isset($sugarFields[$sObject])) { |
||
352 | $fields = $this->getApiHelper()->getLeadFields($sObject); |
||
353 | |||
354 | if (null != $fields && !empty($fields)) { |
||
355 | if (isset($fields['module_fields']) && !empty($fields['module_fields'])) { |
||
356 | //6.x/community |
||
357 | |||
358 | foreach ($fields['module_fields'] as $fieldInfo) { |
||
359 | if (isset($fieldInfo['name']) && (!in_array($fieldInfo['type'], ['id', 'assigned_user_name', 'link', 'relate']) || ('id' == $fieldInfo['type'] && 'id' == $fieldInfo['name']) |
||
360 | ) |
||
361 | ) { |
||
362 | $type = 'string'; |
||
363 | $fieldName = (false === strpos($fieldInfo['name'], |
||
364 | 'webtolead_email')) ? $fieldInfo['name'] : str_replace('webtolead_', |
||
365 | '', $fieldInfo['name']); |
||
366 | // make these congruent as some come in with colons and some do not |
||
367 | $label = str_replace(':', '', $fieldInfo['label']); |
||
368 | if ('company' !== $sObject) { |
||
369 | $sugarFields[$sObject][$fieldName.'__'.$sObject] = [ |
||
370 | 'type' => $type, |
||
371 | 'label' => $sObject.'-'.$label, |
||
372 | 'required' => $isRequired($fieldInfo, $sObject), |
||
373 | 'group' => $sObject, |
||
374 | 'optionLabel' => $fieldInfo['label'], |
||
375 | ]; |
||
376 | } else { |
||
377 | $sugarFields[$sObject][$fieldName] = [ |
||
378 | 'type' => $type, |
||
379 | 'label' => $label, |
||
380 | 'required' => $isRequired($fieldInfo, $sObject), |
||
381 | ]; |
||
382 | } |
||
383 | } |
||
384 | } |
||
385 | } elseif (isset($fields['fields']) && !empty($fields['fields'])) { |
||
386 | //7.x |
||
387 | foreach ($fields['fields'] as $fieldInfo) { |
||
388 | if (isset($fieldInfo['name']) && empty($fieldInfo['readonly']) |
||
389 | && (!in_array( |
||
390 | $fieldInfo['type'], |
||
391 | ['id', 'team_list', 'link', 'relate'] |
||
392 | ) |
||
393 | || |
||
394 | ('id' == $fieldInfo['type'] && 'id' == $fieldInfo['name']) |
||
395 | ) |
||
396 | ) { |
||
397 | if (!empty($fieldInfo['comment'])) { |
||
398 | $label = $fieldInfo['comment']; |
||
399 | } elseif (!empty($fieldInfo['help'])) { |
||
400 | $label = $fieldInfo['help']; |
||
401 | } else { |
||
402 | $label = ucfirst(str_replace('_', ' ', $fieldInfo['name'])); |
||
403 | } |
||
404 | // make these congruent as some come in with colons and some do not |
||
405 | $label = str_replace(':', '', $label); |
||
406 | |||
407 | $fieldName = (false === strpos($fieldInfo['name'], 'webtolead_email')) |
||
408 | ? $fieldInfo['name'] |
||
409 | : str_replace( |
||
410 | 'webtolead_', |
||
411 | '', |
||
412 | $fieldInfo['name'] |
||
413 | ); |
||
414 | |||
415 | $type = 'string'; |
||
416 | if ('company' !== $sObject) { |
||
417 | $sugarFields[$sObject][$fieldName.'__'.$sObject] = [ |
||
418 | 'type' => $type, |
||
419 | 'label' => $sObject.'-'.$label, |
||
420 | 'required' => $isRequired($fieldInfo, $sObject), |
||
421 | 'group' => $sObject, |
||
422 | 'optionLabel' => $label, |
||
423 | ]; |
||
424 | } else { |
||
425 | $sugarFields[$sObject][$fieldName] = [ |
||
426 | 'type' => $type, |
||
427 | 'label' => $label, |
||
428 | 'required' => $isRequired($fieldInfo, $sObject), |
||
429 | ]; |
||
430 | } |
||
431 | } |
||
432 | } |
||
433 | } |
||
434 | } |
||
435 | $this->cache->set('leadFields'.$cacheSuffix, $sugarFields[$sObject]); |
||
436 | } |
||
437 | } else { |
||
438 | throw new ApiErrorException($this->authorizationError); |
||
439 | } |
||
440 | } |
||
441 | } |
||
442 | } catch (\Exception $e) { |
||
443 | $this->logIntegrationError($e); |
||
444 | |||
445 | if (!$silenceExceptions) { |
||
446 | throw $e; |
||
447 | } |
||
448 | } |
||
449 | |||
450 | return $sugarFields; |
||
451 | } |
||
452 | |||
453 | /** |
||
454 | * @param $params |
||
455 | * |
||
456 | * @return mixed |
||
457 | */ |
||
458 | public function getFetchQuery($params) |
||
459 | { |
||
460 | return $params; |
||
461 | } |
||
462 | |||
463 | /** |
||
464 | * @param array $params |
||
465 | * @param array|null $query |
||
466 | * |
||
467 | * @return int|null |
||
468 | */ |
||
469 | public function getCompanies($params = [], $query = null, $executed = null) |
||
470 | { |
||
471 | $executed = null; |
||
472 | |||
473 | $sugarObject = 'Accounts'; |
||
474 | $params['max_results'] = 100; |
||
475 | if (!isset($params['offset'])) { |
||
476 | //First call |
||
477 | $params['offset'] = 0; |
||
478 | } |
||
479 | |||
480 | $query = $params; |
||
481 | |||
482 | try { |
||
483 | if ($this->isAuthorized()) { |
||
484 | $result = $this->getApiHelper()->getLeads($query, $sugarObject); |
||
485 | $params['offset'] = $result['next_offset']; |
||
486 | $executed += $this->amendLeadDataBeforeMauticPopulate($result, $sugarObject); |
||
487 | if ( |
||
488 | (isset($result['total_count']) && $result['total_count'] > $params['offset']) //Sugar 6 |
||
489 | || (!isset($result['total_count']) && $params['offset'] > -1)) { //Sugar 7 |
||
490 | $result = null; |
||
491 | $executed += $this->getCompanies($params, null, $executed); |
||
492 | } |
||
493 | |||
494 | return $executed; |
||
495 | } |
||
496 | } catch (\Exception $e) { |
||
497 | $this->logIntegrationError($e); |
||
498 | } |
||
499 | |||
500 | return $executed; |
||
501 | } |
||
502 | |||
503 | /** |
||
504 | * @param array $params |
||
505 | * |
||
506 | * @return int|null |
||
507 | * |
||
508 | * @throws \Exception |
||
509 | * To be modified |
||
510 | */ |
||
511 | public function pushLeadActivity($params = []) |
||
512 | { |
||
513 | $executed = null; |
||
514 | |||
515 | $query = $this->getFetchQuery($params); |
||
516 | $config = $this->mergeConfigToFeatureSettings([]); |
||
517 | |||
518 | /** @var SugarApi $apiHelper */ |
||
519 | $apiHelper = $this->getApiHelper(); |
||
520 | |||
521 | $sugarObjects[] = 'Leads'; |
||
522 | if (isset($config['objects']) && !empty($config['objects'])) { |
||
523 | $sugarObjects = $config['objects']; |
||
524 | } |
||
525 | |||
526 | /** @var IntegrationEntityRepository $integrationEntityRepo */ |
||
527 | $integrationEntityRepo = $this->em->getRepository('MauticPluginBundle:IntegrationEntity'); |
||
528 | $startDate = new \DateTime($query['start']); |
||
529 | $endDate = new \DateTime($query['end']); |
||
530 | $limit = 100; |
||
531 | |||
532 | foreach ($sugarObjects as $object) { |
||
533 | try { |
||
534 | if ($this->isAuthorized()) { |
||
535 | // Get first batch |
||
536 | $start = 0; |
||
537 | $sugarIds = $integrationEntityRepo->getIntegrationsEntityId( |
||
538 | 'Sugarcrm', |
||
539 | $object, |
||
540 | 'lead', |
||
541 | null, |
||
542 | $startDate->format('Y-m-d H:i:s'), |
||
543 | $endDate->format('Y-m-d H:i:s'), |
||
544 | true, |
||
545 | $start, |
||
546 | $limit |
||
547 | ); |
||
548 | |||
549 | while (!empty($sugarIds)) { |
||
550 | $executed += count($sugarIds); |
||
551 | |||
552 | // Extract a list of lead Ids |
||
553 | $leadIds = []; |
||
554 | foreach ($sugarIds as $ids) { |
||
555 | $leadIds[] = $ids['internal_entity_id']; |
||
556 | } |
||
557 | |||
558 | // Collect lead activity for this batch |
||
559 | $leadActivity = $this->getLeadData( |
||
560 | $startDate, |
||
561 | $endDate, |
||
562 | $leadIds |
||
563 | ); |
||
564 | |||
565 | $sugarLeadData = []; |
||
566 | foreach ($sugarIds as $ids) { |
||
567 | $leadId = $ids['internal_entity_id']; |
||
568 | if (isset($leadActivity[$leadId])) { |
||
569 | $sugarId = $ids['integration_entity_id']; |
||
570 | $sugarLeadData[$sugarId] = $leadActivity[$leadId]; |
||
571 | $sugarLeadData[$sugarId]['id'] = $ids['integration_entity_id']; |
||
572 | $sugarLeadData[$sugarId]['leadId'] = $ids['internal_entity_id']; |
||
573 | $sugarLeadData[$sugarId]['leadUrl'] = $this->router->generate( |
||
574 | 'mautic_plugin_timeline_view', |
||
575 | ['integration' => 'Sugarcrm', 'leadId' => $leadId], |
||
576 | UrlGeneratorInterface::ABSOLUTE_URL |
||
577 | ); |
||
578 | } |
||
579 | } |
||
580 | |||
581 | if (!empty($sugarLeadData)) { |
||
582 | $apiHelper->createLeadActivity($sugarLeadData, $object); |
||
583 | } |
||
584 | |||
585 | // Get the next batch |
||
586 | $start += $limit; |
||
587 | $sugarIds = $integrationEntityRepo->getIntegrationsEntityId( |
||
588 | 'Sugarcrm', |
||
589 | $object, |
||
590 | 'lead', |
||
591 | null, |
||
592 | $startDate->format('Y-m-d H:i:s'), |
||
593 | $endDate->format('Y-m-d H:i:s'), |
||
594 | true, |
||
595 | $start, |
||
596 | $limit |
||
597 | ); |
||
598 | } |
||
599 | } |
||
600 | } catch (\Exception $e) { |
||
601 | $this->logIntegrationError($e); |
||
602 | } |
||
603 | } |
||
604 | |||
605 | return $executed; |
||
606 | } |
||
607 | |||
608 | /** |
||
609 | * @param array $params |
||
610 | * @param array|null $query |
||
611 | * |
||
612 | * @return int|null |
||
613 | */ |
||
614 | public function getLeads($params = [], $query = null, &$executed = null, $result = [], $object = 'Leads') |
||
615 | { |
||
616 | $params['max_results'] = 100; |
||
617 | $config = $this->mergeConfigToFeatureSettings([]); |
||
618 | |||
619 | if (!isset($params['offset'])) { |
||
620 | //First call |
||
621 | $params['offset'] = 0; |
||
622 | } |
||
623 | $query = $params; |
||
624 | |||
625 | try { |
||
626 | if ($this->isAuthorized()) { |
||
627 | if ('Activity' !== $object and 'company' !== $object) { |
||
628 | $result = $this->getApiHelper()->getLeads($query, $object); |
||
629 | $params['offset'] = $result['next_offset']; |
||
630 | $executed += $this->amendLeadDataBeforeMauticPopulate($result, $object); |
||
631 | if ( |
||
632 | (isset($result['total_count']) && $result['total_count'] > $params['offset']) //Sugar 6 |
||
633 | || (!isset($result['total_count']) && $params['offset'] > -1)) { //Sugar 7 |
||
634 | $params['object'] = $object; |
||
635 | $executed += $this->getLeads($params, null, $executed, [], $object); |
||
636 | } |
||
637 | } |
||
638 | |||
639 | return $executed; |
||
640 | } |
||
641 | } catch (\Exception $e) { |
||
642 | $this->logIntegrationError($e); |
||
643 | } |
||
644 | |||
645 | return $executed; |
||
646 | } |
||
647 | |||
648 | /** |
||
649 | * @param $response |
||
650 | * |
||
651 | * @return string |
||
652 | */ |
||
653 | public function getErrorsFromResponse($response) |
||
654 | { |
||
655 | if ('6' == $this->keys['version']) { |
||
656 | if (!empty($response['name'])) { |
||
657 | return $response['description']; |
||
658 | } else { |
||
659 | return $this->translator->trans('mautic.integration.error.genericerror', [], 'flashes'); |
||
660 | } |
||
661 | } else { |
||
662 | return parent::getErrorsFromResponse($response); |
||
663 | } |
||
664 | } |
||
665 | |||
666 | /** |
||
667 | * {@inheritdoc} |
||
668 | * |
||
669 | * @return string |
||
670 | */ |
||
671 | public function getAuthenticationType() |
||
672 | { |
||
673 | return (isset($this->keys['version']) && '6' == $this->keys['version']) ? 'rest' : 'oauth2'; |
||
674 | } |
||
675 | |||
676 | /** |
||
677 | * {@inheritdoc} |
||
678 | * |
||
679 | * @return bool |
||
680 | */ |
||
681 | public function getDataPriority() |
||
682 | { |
||
683 | return true; |
||
684 | } |
||
685 | |||
686 | /** |
||
687 | * @param $url |
||
688 | * @param $parameters |
||
689 | * @param $method |
||
690 | * @param $settings |
||
691 | * @param $authType |
||
692 | * |
||
693 | * @return array |
||
694 | */ |
||
695 | public function prepareRequest($url, $parameters, $method, $settings, $authType) |
||
696 | { |
||
697 | if ('oauth2' == $authType && empty($settings['authorize_session']) && isset($this->keys['access_token'])) { |
||
698 | // Append the access token as the oauth-token header |
||
699 | $headers = [ |
||
700 | "oauth-token: {$this->keys['access_token']}", |
||
701 | ]; |
||
702 | |||
703 | return [$parameters, $headers]; |
||
704 | } else { |
||
705 | return parent::prepareRequest($url, $parameters, $method, $settings, $authType); |
||
706 | } |
||
707 | } |
||
708 | |||
709 | /** |
||
710 | * {@inheritdoc} |
||
711 | * |
||
712 | * @return bool |
||
713 | */ |
||
714 | public function isAuthorized() |
||
715 | { |
||
716 | if (!$this->isConfigured()) { |
||
717 | return false; |
||
718 | } |
||
719 | |||
720 | if (!isset($this->keys['version'])) { |
||
721 | return false; |
||
722 | } |
||
723 | |||
724 | if ('6' == $this->keys['version']) { |
||
725 | $loginParams = [ |
||
726 | 'user_auth' => [ |
||
727 | 'user_name' => $this->keys['username'], |
||
728 | 'password' => md5($this->keys['password']), |
||
729 | 'version' => '1', |
||
730 | ], |
||
731 | 'application_name' => 'Mautic', |
||
732 | 'name_value_list' => [], |
||
733 | 'method' => 'login', |
||
734 | 'input_type' => 'JSON', |
||
735 | 'response_type' => 'JSON', |
||
736 | ]; |
||
737 | $parameters = [ |
||
738 | 'method' => 'login', |
||
739 | 'input_type' => 'JSON', |
||
740 | 'response_type' => 'JSON', |
||
741 | 'rest_data' => json_encode($loginParams), |
||
742 | ]; |
||
743 | |||
744 | $settings['auth_type'] = 'rest'; |
||
745 | $settings['authorize_session'] = true; |
||
746 | |||
747 | $response = $this->makeRequest($this->getAccessTokenUrl(), $parameters, 'GET', $settings); |
||
748 | |||
749 | unset($response['module'], $response['name_value_list']); |
||
750 | $error = $this->extractAuthKeys($response, 'id'); |
||
751 | |||
752 | $this->authorizationError = $error; |
||
753 | |||
754 | return empty($error); |
||
755 | } else { |
||
756 | if ($this->isConfigured()) { |
||
757 | // SugarCRM 7 uses password grant type so login each time to ensure session is valid |
||
758 | $this->authCallback(); |
||
759 | } |
||
760 | |||
761 | return parent::isAuthorized(); |
||
762 | } |
||
763 | } |
||
764 | |||
765 | /** |
||
766 | * {@inheritdoc} |
||
767 | * |
||
768 | * @param $data |
||
769 | */ |
||
770 | public function prepareResponseForExtraction($data) |
||
771 | { |
||
772 | // Extract expiry and set expires for 7.x |
||
773 | if (is_array($data) && isset($data['expires_in'])) { |
||
774 | $data['expires'] = $data['expires_in'] + time(); |
||
775 | } |
||
776 | |||
777 | return $data; |
||
778 | } |
||
779 | |||
780 | /** |
||
781 | * Amend mapped lead data before creating to Mautic. |
||
782 | * |
||
783 | * @param array $data |
||
784 | * @param string $object |
||
785 | * |
||
786 | * @return int |
||
787 | */ |
||
788 | public function amendLeadDataBeforeMauticPopulate($data, $object) |
||
789 | { |
||
790 | $settings['feature_settings']['objects'][] = $object; |
||
791 | $fields = array_keys($this->getAvailableLeadFields($settings)); |
||
792 | $params['fields'] = implode(',', $fields); |
||
793 | |||
794 | $count = 0; |
||
795 | $entity = null; |
||
796 | |||
797 | /** @var IntegrationEntityRepository $integrationEntityRepo */ |
||
798 | $integrationEntityRepo = $this->em->getRepository('MauticPluginBundle:IntegrationEntity'); |
||
799 | $companyRepo = $this->em->getRepository('MauticLeadBundle:Company'); |
||
800 | |||
801 | $sugarRejectedLeads = []; |
||
802 | if (isset($data['entry_list'])) { |
||
803 | $SUGAR_VERSION = '6'; |
||
804 | $RECORDS_LIST_NAME = 'entry_list'; |
||
805 | $MODULE_FIELD_NAME = 'module_name'; |
||
806 | } |
||
807 | if (isset($data['records'])) { |
||
808 | $SUGAR_VERSION = '7'; |
||
809 | $RECORDS_LIST_NAME = 'records'; |
||
810 | $MODULE_FIELD_NAME = '_module'; |
||
811 | } |
||
812 | |||
813 | if (isset($data[$RECORDS_LIST_NAME]) and 'Activity' !== $object) { |
||
814 | //Get assigned user ids |
||
815 | $assignedUserIds = []; |
||
816 | $onwerEmailByAssignedUserId = []; |
||
817 | if ('Leads' == $object || 'Contacts' == $object || 'Accounts' == $object) { |
||
818 | foreach ($data[$RECORDS_LIST_NAME] as $record) { |
||
819 | if ('6' == $SUGAR_VERSION) { |
||
820 | foreach ($record['name_value_list'] as $item) { |
||
821 | if ('assigned_user_id' == $item['name'] && $item['value'] && '' != $item['value']) { |
||
822 | $assignedUserIds[] = $item['value']; |
||
823 | } |
||
824 | } |
||
825 | } else { |
||
826 | if (isset($record['assigned_user_id']) && '' != $record['assigned_user_id']) { |
||
827 | $assignedUserIds[] = $record['assigned_user_id']; |
||
828 | } |
||
829 | } |
||
830 | } |
||
831 | } |
||
832 | if (!empty($assignedUserIds)) { |
||
833 | $assignedUserIds = array_unique($assignedUserIds); |
||
834 | $onwerEmailByAssignedUserId = $this->getApiHelper()->getEmailBySugarUserId(['ids' => $assignedUserIds]); |
||
835 | } |
||
836 | |||
837 | //Get all leads emails |
||
838 | $checkEmailsInSugar = []; |
||
839 | if ('Leads' == $object) { |
||
840 | if ('6' == $SUGAR_VERSION) { |
||
841 | foreach ($data[$RECORDS_LIST_NAME] as $record) { |
||
842 | foreach ($record['name_value_list'] as $item) { |
||
843 | if ('email1' == $item['name'] && $item['value'] && '' != $item['value']) { |
||
844 | $checkEmailsInSugar[] = $item['value']; |
||
845 | } |
||
846 | } |
||
847 | } |
||
848 | } else { |
||
849 | if (isset($record['email1']) && '' != $record['email1']) { |
||
850 | $checkEmailsInSugar[] = $record['email1']; |
||
851 | } |
||
852 | } |
||
853 | } |
||
854 | if (!empty($checkEmailsInSugar)) { |
||
855 | $sugarLeads = $this->getApiHelper()->getLeads(['checkemail_contacts' => $checkEmailsInSugar, 'offset' => 0, 'max_results' => 1000], 'Contacts'); |
||
856 | if (isset($sugarLeads[$RECORDS_LIST_NAME])) { |
||
857 | foreach ($sugarLeads[$RECORDS_LIST_NAME] as $record) { |
||
858 | $sugarLeadRecord = []; |
||
859 | if ('6' == $SUGAR_VERSION) { |
||
860 | foreach ($record['name_value_list'] as $item) { |
||
861 | if ('email1' == $item['name'] && $item['value'] && '' != $item['value']) { |
||
862 | $sugarRejectedLeads[] = $item['value']; |
||
863 | } |
||
864 | } |
||
865 | } else { |
||
866 | if (isset($record['email1']) && '' != $record['email1']) { |
||
867 | $sugarRejectedLeads[] = $record['email1']; |
||
868 | } |
||
869 | } |
||
870 | } |
||
871 | } |
||
872 | } |
||
873 | |||
874 | foreach ($data[$RECORDS_LIST_NAME] as $record) { |
||
875 | $integrationEntities = []; |
||
876 | $dataObject = []; |
||
877 | if (isset($record[$MODULE_FIELD_NAME]) && 'Accounts' == $record[$MODULE_FIELD_NAME]) { |
||
878 | $newName = ''; |
||
879 | } else { |
||
880 | $newName = '__'.$object; |
||
881 | } |
||
882 | if ('6' == $SUGAR_VERSION) { |
||
883 | foreach ($record['name_value_list'] as $item) { |
||
884 | if ('Activity' !== $object) { |
||
885 | if ($this->checkIfSugarCrmMultiSelectString($item['value'])) { |
||
886 | $convertedMultiSelectString = $this->convertSuiteCrmToMauticMultiSelect($item['value']); |
||
887 | $dataObject[$item['name'].$newName] = $convertedMultiSelectString; |
||
888 | } else { |
||
889 | $dataObject[$item['name'].$newName] = $item['value']; |
||
890 | } |
||
891 | if ('date_entered' == $item['name']) { |
||
892 | $itemDateEntered = new \DateTime($item['value']); |
||
893 | } |
||
894 | if ('date_modified' == $item['name']) { |
||
895 | $itemDateModified = new \DateTime($item['value']); |
||
896 | } |
||
897 | } |
||
898 | } |
||
899 | } else { |
||
900 | if ('Activity' !== $object) { |
||
901 | if (isset($record['date_entered']) && '' != $record['date_entered']) { |
||
902 | $itemDateEntered = new \DateTime($record['date_entered']); |
||
903 | } |
||
904 | if (isset($record['date_modified']) && '' != $record['date_modified']) { |
||
905 | $itemDateEntered = new \DateTime($record['date_modified']); |
||
906 | } |
||
907 | foreach ($record as $k => $item) { |
||
908 | $dataObject[$k.$newName] = $item; |
||
909 | } |
||
910 | } |
||
911 | } |
||
912 | if ('Leads' == $object && isset($dataObject['email1__Leads']) && null != $dataObject['email1__Leads'] |
||
913 | && '' != $dataObject['email1__Leads'] && in_array($dataObject['email1__Leads'], $sugarRejectedLeads)) { |
||
914 | continue; //Lead email is already in Sugar Contacts. Do not carry on |
||
915 | } |
||
916 | |||
917 | if (!empty($dataObject)) { |
||
918 | if ('Leads' == $object or 'Contacts' == $object) { |
||
919 | if (isset($dataObject['assigned_user_id'.'__'.$object])) { |
||
920 | $auid = $dataObject['assigned_user_id'.'__'.$object]; |
||
921 | if (isset($onwerEmailByAssignedUserId[$auid])) { |
||
922 | $dataObject['owner_email'] = $onwerEmailByAssignedUserId[$auid]; |
||
923 | } |
||
924 | } |
||
925 | $mauticObjectReference = 'lead'; |
||
926 | $entity = $this->getMauticLead($dataObject, true, null, null, $object); |
||
927 | $detachClass = Lead::class; |
||
928 | $company = null; |
||
929 | $this->fetchDncToMautic($entity, $data); |
||
930 | if ($entity && isset($dataObject['account_id'.$newName]) && '' != trim($dataObject['account_id'.$newName])) { |
||
931 | $integrationCompanyEntity = $integrationEntityRepo->findOneBy( |
||
932 | [ |
||
933 | 'integration' => 'Sugarcrm', |
||
934 | 'integrationEntity' => 'Accounts', |
||
935 | 'internalEntity' => 'company', |
||
936 | 'integrationEntityId' => $dataObject['account_id'.$newName], |
||
937 | ] |
||
938 | ); |
||
939 | if (isset($integrationCompanyEntity)) { |
||
940 | $companyId = $integrationCompanyEntity->getInternalEntityId(); |
||
941 | $company = $companyRepo->find($companyId); |
||
942 | |||
943 | $this->companyModel->addLeadToCompany($company, $entity); |
||
944 | $this->em->clear(Company::class); |
||
945 | $this->em->detach($entity); |
||
946 | } |
||
947 | } |
||
948 | } elseif ('Accounts' === $object) { |
||
949 | $entity = $this->getMauticCompany($dataObject, $object); |
||
950 | $detachClass = Company::class; |
||
951 | $mauticObjectReference = 'company'; |
||
952 | } else { |
||
953 | $this->logIntegrationError( |
||
954 | new \Exception( |
||
955 | sprintf('Received an unexpected object without an internalObjectReference "%s"', $object) |
||
956 | ) |
||
957 | ); |
||
958 | |||
959 | continue; |
||
960 | } |
||
961 | |||
962 | if ($entity) { |
||
963 | $integrationId = $integrationEntityRepo->getIntegrationsEntityId( |
||
964 | 'Sugarcrm', |
||
965 | $object, |
||
966 | $mauticObjectReference, |
||
967 | $entity->getId() |
||
968 | ); |
||
969 | |||
970 | if (null == $integrationId) { |
||
971 | $integrationEntity = new IntegrationEntity(); |
||
972 | $integrationEntity->setDateAdded(new \DateTime()); |
||
973 | $integrationEntity->setLastSyncDate(new \DateTime()); |
||
974 | $integrationEntity->setIntegration('Sugarcrm'); |
||
975 | $integrationEntity->setIntegrationEntity($object); |
||
976 | $integrationEntity->setIntegrationEntityId($record['id']); |
||
977 | $integrationEntity->setInternalEntity($mauticObjectReference); |
||
978 | $integrationEntity->setInternalEntityId($entity->getId()); |
||
979 | $integrationEntities[] = $integrationEntity; |
||
980 | } else { |
||
981 | $integrationEntity = $integrationEntityRepo->getEntity($integrationId[0]['id']); |
||
982 | $integrationEntity->setLastSyncDate(new \DateTime()); |
||
983 | $integrationEntities[] = $integrationEntity; |
||
984 | } |
||
985 | $this->em->detach($entity); |
||
986 | $this->em->clear($detachClass); |
||
987 | unset($entity); |
||
988 | } else { |
||
989 | continue; |
||
990 | } |
||
991 | ++$count; |
||
992 | } |
||
993 | |||
994 | $this->em->getRepository('MauticPluginBundle:IntegrationEntity')->saveEntities($integrationEntities); |
||
995 | $this->em->clear('Mautic\PluginBundle\Entity\IntegrationEntity'); |
||
996 | } |
||
997 | unset($data); |
||
998 | unset($integrationEntities); |
||
999 | unset($dataObject); |
||
1000 | } |
||
1001 | |||
1002 | return $count; |
||
1003 | } |
||
1004 | |||
1005 | /** |
||
1006 | * @param \Mautic\PluginBundle\Integration\Form|FormBuilder $builder |
||
1007 | * @param array $data |
||
1008 | * @param string $formArea |
||
1009 | */ |
||
1010 | public function appendToForm(&$builder, $data, $formArea) |
||
1011 | { |
||
1012 | if ('keys' == $formArea) { |
||
1013 | $builder->add('version', ButtonGroupType::class, [ |
||
1014 | 'choices' => [ |
||
1015 | '6.x/community' => '6', |
||
1016 | '7.x' => '7', |
||
1017 | ], |
||
1018 | 'label' => 'mautic.sugarcrm.form.version', |
||
1019 | 'constraints' => [ |
||
1020 | new NotBlank([ |
||
1021 | 'message' => 'mautic.core.value.required', |
||
1022 | ]), |
||
1023 | ], |
||
1024 | 'required' => true, |
||
1025 | ]); |
||
1026 | } |
||
1027 | if ('features' == $formArea) { |
||
1028 | $builder->add( |
||
1029 | 'updateOwner', |
||
1030 | ChoiceType::class, |
||
1031 | [ |
||
1032 | 'choices' => [ |
||
1033 | 'mautic.sugarcrm.updateOwner' => 'updateOwner', |
||
1034 | ], |
||
1035 | 'expanded' => true, |
||
1036 | 'multiple' => true, |
||
1037 | 'label' => 'mautic.sugarcrm.form.updateOwner', |
||
1038 | 'label_attr' => ['class' => 'control-label'], |
||
1039 | 'placeholder' => false, |
||
1040 | 'required' => false, |
||
1041 | 'attr' => [ |
||
1042 | 'onclick' => 'Mautic.postForm(mQuery(\'form[name="integration_details"]\'),\'\');', |
||
1043 | ], |
||
1044 | ] |
||
1045 | ); |
||
1046 | |||
1047 | $builder->add( |
||
1048 | 'updateDnc', |
||
1049 | ChoiceType::class, |
||
1050 | [ |
||
1051 | 'choices' => [ |
||
1052 | 'mautic.sugarcrm.updateDnc' => 'updateDnc', |
||
1053 | ], |
||
1054 | 'expanded' => true, |
||
1055 | 'multiple' => true, |
||
1056 | 'label' => 'mautic.sugarcrm.form.updateDnc', |
||
1057 | 'label_attr' => ['class' => 'control-label'], |
||
1058 | 'placeholder' => false, |
||
1059 | 'required' => false, |
||
1060 | 'attr' => [ |
||
1061 | 'onclick' => 'Mautic.postForm(mQuery(\'form[name="integration_details"]\'),\'\');', |
||
1062 | ], |
||
1063 | ] |
||
1064 | ); |
||
1065 | |||
1066 | $builder->add( |
||
1067 | 'updateBlanks', |
||
1068 | ChoiceType::class, |
||
1069 | [ |
||
1070 | 'choices' => [ |
||
1071 | 'mautic.integrations.blanks' => 'updateBlanks', |
||
1072 | ], |
||
1073 | 'expanded' => true, |
||
1074 | 'multiple' => true, |
||
1075 | 'label' => 'mautic.integrations.form.blanks', |
||
1076 | 'label_attr' => ['class' => 'control-label'], |
||
1077 | 'placeholder' => false, |
||
1078 | 'required' => false, |
||
1079 | ] |
||
1080 | ); |
||
1081 | |||
1082 | $builder->add( |
||
1083 | 'objects', |
||
1084 | ChoiceType::class, |
||
1085 | [ |
||
1086 | 'choices' => [ |
||
1087 | 'mautic.sugarcrm.object.lead' => 'Leads', |
||
1088 | 'mautic.sugarcrm.object.contact' => 'Contacts', |
||
1089 | 'mautic.sugarcrm.object.company' => 'company', |
||
1090 | ], |
||
1091 | 'expanded' => true, |
||
1092 | 'multiple' => true, |
||
1093 | 'label' => 'mautic.sugarcrm.form.objects_to_pull_from', |
||
1094 | 'label_attr' => ['class' => ''], |
||
1095 | 'placeholder' => false, |
||
1096 | 'required' => false, |
||
1097 | ] |
||
1098 | ); |
||
1099 | |||
1100 | $builder->add( |
||
1101 | 'activityEvents', |
||
1102 | ChoiceType::class, |
||
1103 | [ |
||
1104 | 'choices' => array_flip($this->leadModel->getEngagementTypes()), // Choice type expects labels as keys |
||
1105 | 'label' => 'mautic.salesforce.form.activity_included_events', |
||
1106 | 'label_attr' => [ |
||
1107 | 'class' => 'control-label', |
||
1108 | 'data-toggle' => 'tooltip', |
||
1109 | 'title' => $this->translator->trans('mautic.salesforce.form.activity.events.tooltip'), |
||
1110 | ], |
||
1111 | 'multiple' => true, |
||
1112 | 'empty_data' => ['point.gained', 'form.submitted', 'email.read'], // BC with pre 2.11.0 |
||
1113 | 'required' => false, |
||
1114 | ] |
||
1115 | ); |
||
1116 | } |
||
1117 | } |
||
1118 | |||
1119 | /** |
||
1120 | * @param \Mautic\LeadBundle\Entity\Lead $lead |
||
1121 | * @param array $config |
||
1122 | * |
||
1123 | * @return array|bool |
||
1124 | */ |
||
1125 | public function pushLead($lead, $config = []) |
||
1126 | { |
||
1127 | $config = $this->mergeConfigToFeatureSettings($config); |
||
1128 | |||
1129 | if (empty($config['leadFields'])) { |
||
1130 | return []; |
||
1131 | } |
||
1132 | |||
1133 | $object = 'Leads'; //Sugar objects, default is Leads |
||
1134 | |||
1135 | //Check if lead has alredy been synched |
||
1136 | /** @var IntegrationEntityRepository $integrationEntityRepo */ |
||
1137 | $integrationEntityRepo = $this->em->getRepository('MauticPluginBundle:IntegrationEntity'); |
||
1138 | //Check if it is a sugar CRM alredy synched lead |
||
1139 | $integrationId = $integrationEntityRepo->getIntegrationsEntityId('Sugarcrm', $object, 'lead', $lead->getId()); |
||
1140 | if (empty($integrationId)) { |
||
1141 | //Check if it is a sugar CRM alredy synched lead |
||
1142 | $integrationId = $integrationEntityRepo->getIntegrationsEntityId('Sugarcrm', 'Contacts', 'lead', $lead->getId()); |
||
1143 | if (!empty($integrationId)) { |
||
1144 | $object = 'Contacts'; |
||
1145 | } |
||
1146 | } |
||
1147 | if (!empty($integrationId)) { |
||
1148 | $integrationEntity = $integrationEntityRepo->getEntity($integrationId[0]['id']); |
||
1149 | $lastSyncDate = $integrationEntity->getLastSyncDate(); |
||
1150 | $addedSyncDate = $integrationEntity->getDateAdded(); |
||
1151 | if ($addedSyncDate > $lastSyncDate) { |
||
1152 | $lastSyncDate = $addedSyncDate; |
||
1153 | } |
||
1154 | |||
1155 | $leadDateModified = $lead->getDateModified(); |
||
1156 | $leadDateAdded = $lead->getDateAdded(); |
||
1157 | $leadLastDate = $leadDateModified; |
||
1158 | if ($leadDateAdded > $leadDateModified) { |
||
1159 | $leadLastDate = $leadDateAdded; |
||
1160 | } |
||
1161 | |||
1162 | if ($lastSyncDate >= $leadLastDate) { |
||
1163 | return false; |
||
1164 | } //Do not push lead if it was already synched |
||
1165 | } |
||
1166 | |||
1167 | $fieldsToUpdateInSugar = isset($config['update_mautic']) ? array_keys($config['update_mautic'], 0) : []; |
||
1168 | $leadSugarFieldsToCreate = $this->cleanSugarData($config, array_keys($config['leadFields']), $object); |
||
1169 | $fieldsToUpdateInLeadsSugar = $this->cleanSugarData($config, $fieldsToUpdateInSugar, $object); |
||
1170 | $leadFields = array_intersect_key($leadSugarFieldsToCreate, $fieldsToUpdateInLeadsSugar); |
||
1171 | |||
1172 | $mappedData[$object] = $this->populateLeadData($lead, ['leadFields' => $leadFields, 'object' => $object]); |
||
1173 | |||
1174 | $this->amendLeadDataBeforePush($mappedData[$object]); |
||
1175 | |||
1176 | if (empty($mappedData[$object])) { |
||
1177 | return false; |
||
1178 | } |
||
1179 | |||
1180 | if (!empty($integrationId)) { |
||
1181 | $integrationEntity = $integrationEntityRepo->findOneBy( |
||
1182 | [ |
||
1183 | 'integration' => 'Sugarcrm', |
||
1184 | 'integrationEntity' => $object, |
||
1185 | 'internalEntity' => 'lead', |
||
1186 | 'internalEntityId' => $lead->getId(), |
||
1187 | ] |
||
1188 | ); |
||
1189 | |||
1190 | $mappedData[$object]['id'] = $integrationEntity->getIntegrationEntityId(); |
||
1191 | } |
||
1192 | try { |
||
1193 | if ($this->isAuthorized()) { |
||
1194 | if (!is_null($lead->getOwner())) { |
||
1195 | $sugarOwnerId = $this->getApiHelper()->getIdBySugarEmail(['emails' => [$lead->getOwner()->getEmail()]]); |
||
0 ignored issues
–
show
Bug
introduced
by
Loading history...
|
|||
1196 | if (!empty($sugarOwnerId)) { |
||
1197 | $mappedData[$object]['assigned_user_id'] = array_values($sugarOwnerId)[0]; |
||
1198 | } |
||
1199 | } |
||
1200 | $createdLeadData = $this->getApiHelper()->createLead($mappedData[$object], $lead); |
||
1201 | if (isset($createdLeadData['id'])) { |
||
1202 | if (empty($integrationId)) { |
||
1203 | $integrationEntity = new IntegrationEntity(); |
||
1204 | $integrationEntity->setDateAdded(new \DateTime()); |
||
1205 | $integrationEntity->setLastSyncDate(new \DateTime()); |
||
1206 | $integrationEntity->setIntegration('Sugarcrm'); |
||
1207 | $integrationEntity->setIntegrationEntity($object); |
||
1208 | $integrationEntity->setIntegrationEntityId($createdLeadData['id']); |
||
1209 | $integrationEntity->setInternalEntity('lead'); |
||
1210 | $integrationEntity->setInternalEntityId($lead->getId()); |
||
1211 | } else { |
||
1212 | $integrationEntity = $integrationEntityRepo->getEntity($integrationId[0]['id']); |
||
1213 | } |
||
1214 | $integrationEntity->setLastSyncDate(new \DateTime()); |
||
1215 | $this->em->persist($integrationEntity); |
||
1216 | $this->em->flush($integrationEntity); |
||
1217 | } |
||
1218 | |||
1219 | return true; |
||
1220 | } |
||
1221 | } catch (\Exception $e) { |
||
1222 | $this->logIntegrationError($e); |
||
1223 | } |
||
1224 | |||
1225 | return false; |
||
1226 | } |
||
1227 | |||
1228 | /** |
||
1229 | * Return key recognized by integration. |
||
1230 | * |
||
1231 | * @param $key |
||
1232 | * @param $field |
||
1233 | * |
||
1234 | * @return mixed |
||
1235 | */ |
||
1236 | public function convertLeadFieldKey($key, $field) |
||
1237 | { |
||
1238 | $search = []; |
||
1239 | foreach ($this->objects as $object) { |
||
1240 | $search[] = '__'.$object; |
||
1241 | } |
||
1242 | |||
1243 | return str_replace($search, '', $key); |
||
1244 | } |
||
1245 | |||
1246 | /** |
||
1247 | * @param array $fields |
||
1248 | * @param array $keys |
||
1249 | * @param string $object |
||
1250 | * |
||
1251 | * @return array |
||
1252 | */ |
||
1253 | public function cleanSugarData($fields, $keys, $object) |
||
1254 | { |
||
1255 | $leadFields = []; |
||
1256 | |||
1257 | foreach ($keys as $key) { |
||
1258 | if (strstr($key, '__'.$object)) { |
||
1259 | $newKey = str_replace('__'.$object, '', $key); |
||
1260 | //$leadFields[$object][$newKey] = $fields['leadFields'][$key]; |
||
1261 | $leadFields[$newKey] = $fields['leadFields'][$key]; |
||
1262 | } |
||
1263 | } |
||
1264 | |||
1265 | return $leadFields; |
||
1266 | } |
||
1267 | |||
1268 | /** |
||
1269 | * @param array $params |
||
1270 | * |
||
1271 | * @return mixed |
||
1272 | */ |
||
1273 | public function pushLeads($params = []) |
||
1274 | { |
||
1275 | list($fromDate, $toDate) = $this->getSyncTimeframeDates($params); |
||
1276 | $limit = $params['limit']; |
||
1277 | $config = $this->mergeConfigToFeatureSettings(); |
||
1278 | $integrationEntityRepo = $this->em->getRepository('MauticPluginBundle:IntegrationEntity'); |
||
1279 | $mauticData = $leadsToUpdate = $fields = []; |
||
1280 | $fieldsToUpdateInSugar = isset($config['update_mautic']) ? array_keys($config['update_mautic'], 0) : []; |
||
1281 | $leadFields = $config['leadFields']; |
||
1282 | if (!empty($leadFields)) { |
||
1283 | if ($keys = array_keys($leadFields, 'mauticContactTimelineLink')) { |
||
1284 | foreach ($keys as $key) { |
||
1285 | unset($leadFields[$key]); |
||
1286 | } |
||
1287 | } |
||
1288 | |||
1289 | if ($keys = array_keys($leadFields, 'mauticContactIsContactableByEmail')) { |
||
1290 | foreach ($keys as $key) { |
||
1291 | unset($leadFields[$key]); |
||
1292 | } |
||
1293 | } |
||
1294 | |||
1295 | $fields = implode(', l.', $leadFields); |
||
1296 | $fields = 'l.owner_id,l.'.$fields; |
||
1297 | $result = 0; |
||
1298 | |||
1299 | //Leads fields |
||
1300 | $leadSugarFieldsToCreate = $this->cleanSugarData($config, array_keys($config['leadFields']), 'Leads'); |
||
1301 | $fieldsToUpdateInLeadsSugar = $this->cleanSugarData($config, $fieldsToUpdateInSugar, 'Leads'); |
||
1302 | $leadSugarFields = array_intersect_key($leadSugarFieldsToCreate, $fieldsToUpdateInLeadsSugar); |
||
1303 | |||
1304 | //Contacts fields |
||
1305 | $contactSugarFields = $this->cleanSugarData($config, array_keys($config['leadFields']), 'Contacts'); |
||
1306 | $fieldsToUpdateInContactsSugar = $this->cleanSugarData($config, $fieldsToUpdateInSugar, 'Contacts'); |
||
1307 | $contactSugarFields = array_intersect_key($contactSugarFields, $fieldsToUpdateInContactsSugar); |
||
1308 | |||
1309 | $availableFields = $this->getAvailableLeadFields(['feature_settings' => ['objects' => ['Leads', 'Contacts']]]); |
||
1310 | |||
1311 | //update lead/contact records |
||
1312 | $leadsToUpdate = $integrationEntityRepo->findLeadsToUpdate($this->getName(), 'lead', $fields, $limit, $fromDate, $toDate, ['Contacts', 'Leads']); |
||
1313 | } |
||
1314 | $checkEmailsInSugar = []; |
||
1315 | $deletedSugarLeads = []; |
||
1316 | foreach ($leadsToUpdate as $object => $records) { |
||
1317 | foreach ($records as $lead) { |
||
1318 | if (isset($lead['email']) && !empty($lead['email'])) { |
||
1319 | $lead = $this->getCompoundMauticFields($lead); |
||
1320 | $checkEmailsInSugar[$object][mb_strtolower($lead['email'])] = $lead; |
||
1321 | } |
||
1322 | } |
||
1323 | } |
||
1324 | // Only get the max limit |
||
1325 | if ($limit) { |
||
1326 | $limit -= count($leadsToUpdate); |
||
1327 | } |
||
1328 | |||
1329 | //create lead records |
||
1330 | if (null === $limit || $limit && !empty($fields)) { |
||
1331 | $leadsToCreate = $integrationEntityRepo->findLeadsToCreate('Sugarcrm', $fields, $limit, $fromDate, $toDate); |
||
1332 | foreach ($leadsToCreate as $lead) { |
||
1333 | if (isset($lead['email'])) { |
||
1334 | $lead = $this->getCompoundMauticFields($lead); |
||
1335 | $checkEmailsInSugar['Leads'][mb_strtolower($lead['email'])] = $lead; |
||
1336 | } |
||
1337 | } |
||
1338 | } |
||
1339 | |||
1340 | foreach ($checkEmailsInSugar as $object => $checkObjectEmailsInSugar) { |
||
1341 | list($checkEmailsUpdatedInSugar, $deletedRedords) = $this->getObjectDataToUpdate($checkObjectEmailsInSugar, $mauticData, $availableFields, $contactSugarFields, $leadSugarFields, $object); |
||
1342 | //recheck synced records that might have been deleted in Sugar (deleted records don't come back in the query) |
||
1343 | foreach ($checkEmailsUpdatedInSugar as $key => $deletedSugarRedords) { |
||
1344 | if (isset($deletedSugarRedords['integration_entity_id']) && !empty($deletedSugarRedords['integration_entity_id'])) { |
||
1345 | $deletedSugarLeads[$key] = $deletedSugarRedords['integration_entity_id']; |
||
1346 | } |
||
1347 | unset($checkEmailsUpdatedInSugar[$key]); |
||
1348 | } |
||
1349 | } |
||
1350 | |||
1351 | if (!empty($checkEmailsUpdatedInSugar)) { |
||
1352 | $checkEmailsInSugar = array_merge($checkEmailsUpdatedInSugar, $checkEmailsInSugar); |
||
1353 | } |
||
1354 | // If there are any deleted, mark it as so to prevent them from being queried over and over or recreated |
||
1355 | if ($deletedSugarLeads) { |
||
1356 | $integrationEntityRepo->markAsDeleted($deletedSugarLeads, $this->getName(), 'lead'); |
||
1357 | } |
||
1358 | |||
1359 | // Create any left over |
||
1360 | if ($checkEmailsInSugar && isset($checkEmailsInSugar['Leads'])) { |
||
1361 | list($checkEmailsInSugar, $deletedSugarLeads) = $this->getObjectDataToUpdate($checkEmailsInSugar['Leads'], $mauticData, $availableFields, $contactSugarFields, $leadSugarFields, 'Leads'); |
||
1362 | $ownerAssignedUserIdByEmail = null; |
||
1363 | foreach ($checkEmailsInSugar as $lead) { |
||
1364 | if (isset($lead['email'])) { |
||
1365 | $lead['owner_email'] = $this->getOwnerEmail($lead); |
||
1366 | if ($lead['owner_email']) { |
||
1367 | $ownerAssignedUserIdByEmail = $this->getApiHelper()->getIdBySugarEmail(['emails' => [$lead['owner_email']]]); |
||
1368 | } |
||
1369 | $this->buildCompositeBody( |
||
1370 | $mauticData, |
||
1371 | $availableFields, |
||
1372 | $leadSugarFieldsToCreate, //use all matched fields when creating new records in Sugar |
||
1373 | 'Leads', |
||
1374 | $lead, |
||
1375 | $ownerAssignedUserIdByEmail |
||
1376 | ); |
||
1377 | } |
||
1378 | } |
||
1379 | } |
||
1380 | /** @var SugarcrmApi $apiHelper */ |
||
1381 | $apiHelper = $this->getApiHelper(); |
||
1382 | if (!empty($mauticData)) { |
||
1383 | $result = $apiHelper->syncLeadsToSugar($mauticData); |
||
1384 | } |
||
1385 | |||
1386 | return $this->processCompositeResponse($result); |
||
1387 | } |
||
1388 | |||
1389 | /** |
||
1390 | * Update body to sync. |
||
1391 | */ |
||
1392 | private function pushDncToSugar(array $lead, array &$body) |
||
1393 | { |
||
1394 | $features = $this->settings->getFeatureSettings(); |
||
1395 | // update DNC sync disabled |
||
1396 | if (empty($features['updateDnc'])) { |
||
1397 | return; |
||
1398 | } |
||
1399 | $leadEntity = $this->leadModel->getEntity($lead['internal_entity_id']); |
||
1400 | /** @var \Mautic\LeadBundle\Entity\DoNotContact[] $dncEntries */ |
||
1401 | $dncEntries = $this->doNotContactModel->getDncRepo()->getEntriesByLeadAndChannel($leadEntity, 'email'); |
||
1402 | $sugarDncKeys = array_combine(array_values($this->sugarDncKeys), $this->sugarDncKeys); |
||
1403 | foreach ($dncEntries as $dncEntry) { |
||
1404 | if (empty($sugarDncKeys)) { |
||
1405 | continue; |
||
1406 | } |
||
1407 | // If DNC exists set to 1 |
||
1408 | switch ($dncEntry->getReason()) { |
||
1409 | case 1: |
||
1410 | case 3: |
||
1411 | $body[] = ['name' => 'email_opt_out', 'value' => 1]; |
||
1412 | unset($sugarDncKeys['email_opt_out']); |
||
1413 | break; |
||
1414 | case 2: |
||
1415 | $body[] = ['name' => 'invalid_email', 'value' => 1]; |
||
1416 | unset($sugarDncKeys['invalid_email']); |
||
1417 | break; |
||
1418 | } |
||
1419 | } |
||
1420 | |||
1421 | // uncheck |
||
1422 | // If DNC doesn't exist set to 1 |
||
1423 | if (!empty($sugarDncKeys)) { |
||
1424 | foreach ($sugarDncKeys as $sugarDncKey) { |
||
1425 | $body[] = ['name' => $sugarDncKey, 'value' => 0]; |
||
1426 | } |
||
1427 | } |
||
1428 | } |
||
1429 | |||
1430 | private function fetchDncToMautic(Lead $lead = null, array $data) |
||
1431 | { |
||
1432 | if (is_null($lead)) { |
||
1433 | return; |
||
1434 | } |
||
1435 | |||
1436 | $features = $this->settings->getFeatureSettings(); |
||
1437 | if (empty($features['updateDnc'])) { |
||
1438 | return; |
||
1439 | } |
||
1440 | |||
1441 | // try find opt_out value for lead |
||
1442 | $isContactable = true; |
||
1443 | foreach ($data['relationship_list'] as $relationshipList) { |
||
1444 | foreach ($relationshipList['link_list'] as $links) { |
||
1445 | if ('email_addresses' == $links['name']) { |
||
1446 | foreach ($links['records'] as $records) { |
||
1447 | if (!empty($records['link_value']['email_address']['value']) && $records['link_value']['email_address']['value'] == $lead->getEmail() && !empty($records['link_value']['opt_out']['value'])) { |
||
1448 | $isContactable = false; |
||
1449 | break 3; |
||
1450 | } |
||
1451 | } |
||
1452 | } |
||
1453 | } |
||
1454 | } |
||
1455 | |||
1456 | $reason = \Mautic\LeadBundle\Entity\DoNotContact::UNSUBSCRIBED; |
||
1457 | if (!$isContactable) { |
||
1458 | $this->doNotContactModel->addDncForContact($lead->getId(), 'email', $reason, $this->getName()); |
||
1459 | } else { |
||
1460 | $this->doNotContactModel->removeDncForContact($lead->getId(), 'email', true, $reason); |
||
1461 | } |
||
1462 | } |
||
1463 | |||
1464 | /** |
||
1465 | * @param $checkEmailsInSugar |
||
1466 | * @param $mauticData |
||
1467 | * @param $availableFields |
||
1468 | * @param $contactSugarFields |
||
1469 | * @param $leadSugarFields |
||
1470 | * @param string $object |
||
1471 | * |
||
1472 | * @return array The first element is made up of records that exist in Mautic, but which no longer have a match in CRM. |
||
1473 | * We therefore assume that they've been deleted in CRM and will mark them as deleted in the pushLeads function (~line 1320). |
||
1474 | * The second element contains Ids of records that were explicitly marked as deleted in CRM. ATM, nothing is done with this data. |
||
1475 | */ |
||
1476 | public function getObjectDataToUpdate($checkEmailsInSugar, &$mauticData, $availableFields, $contactSugarFields, $leadSugarFields, $object = 'Leads') |
||
1477 | { |
||
1478 | $config = $this->mergeConfigToFeatureSettings([]); |
||
1479 | $queryParam = ('Leads' == $object) ? 'checkemail' : 'checkemail_contacts'; |
||
1480 | |||
1481 | $sugarLead = $this->getApiHelper()->getLeads([$queryParam => array_keys($checkEmailsInSugar), 'offset' => 0, 'max_results' => 1000], $object); |
||
1482 | $deletedSugarLeads = $sugarLeadRecords = []; |
||
1483 | |||
1484 | if (isset($sugarLead['entry_list'])) { |
||
1485 | //Sugar 6.X |
||
1486 | $sugarLeadRecords = []; |
||
1487 | foreach ($sugarLead['entry_list'] as $k => $record) { |
||
1488 | $sugarLeadRecord = []; |
||
1489 | $sugarLeadRecord['id'] = $record['id']; |
||
1490 | $sugarLeadRecord['module_name'] = $record['module_name']; |
||
1491 | foreach ($record['name_value_list'] as $item) { |
||
1492 | $sugarLeadRecord[$item['name']] = $item['value']; |
||
1493 | } |
||
1494 | if (!isset($sugarLeadRecord['email1'])) { |
||
1495 | foreach ($sugarLead['relationship_list'][$k]['link_list'] as $links) { |
||
1496 | if ('email_addresses' == $links['name']) { |
||
1497 | foreach ($links['records'] as $records) { |
||
1498 | foreach ($records as $contactEmails) { |
||
1499 | foreach ($contactEmails as $anyAddress) { |
||
1500 | if ('email_address' == $anyAddress['name'] && !empty($anyAddress['value'])) { |
||
1501 | $sugarLeadRecord['email1'] = $anyAddress['value']; |
||
1502 | break; |
||
1503 | } |
||
1504 | } |
||
1505 | } |
||
1506 | } |
||
1507 | } |
||
1508 | } |
||
1509 | } |
||
1510 | $sugarLeadRecords[] = $sugarLeadRecord; |
||
1511 | } |
||
1512 | } elseif (isset($sugarLead['records'])) { //Sugar 7 |
||
1513 | $sugarLeadRecords = $sugarLead['records']; |
||
1514 | } |
||
1515 | |||
1516 | foreach ($sugarLeadRecords as $sugarLeadRecord) { |
||
1517 | if ((isset($sugarLeadRecord) && $sugarLeadRecord)) { |
||
1518 | $email = $sugarLeadRecord['email1']; |
||
1519 | $key = mb_strtolower($email); |
||
1520 | $leadOwnerEmails = []; |
||
1521 | if (!empty($checkEmailsInSugar)) { |
||
1522 | foreach ($checkEmailsInSugar as $emailKey => $mauticRecord) { |
||
1523 | if ($key == $emailKey) { |
||
1524 | $isConverted = (isset($sugarLeadRecord['contact_id']) |
||
1525 | && null != $sugarLeadRecord['contact_id'] |
||
1526 | && '' != $sugarLeadRecord['contact_id']); |
||
1527 | |||
1528 | $sugarIdMapping[$checkEmailsInSugar[$key]['internal_entity_id']] = ($isConverted) ? $sugarLeadRecord['contact_id'] : $sugarLeadRecord['id']; |
||
1529 | $lead['owner_email'] = $this->getOwnerEmail($mauticRecord); |
||
1530 | if ($lead['owner_email']) { |
||
1531 | $leadOwnerEmails[] = $lead['owner_email']; |
||
1532 | } |
||
1533 | $ownerAssignedUserIdByEmail = $this->getApiHelper()->getIdBySugarEmail(['emails' => array_unique($leadOwnerEmails)]); |
||
1534 | if (empty($sugarLeadRecord['deleted']) || 0 == $sugarLeadRecord['deleted']) { |
||
1535 | $sugarFieldMappings = $this->prepareFieldsForPush($availableFields); |
||
1536 | |||
1537 | if (isset($sugarFieldMappings['Contacts']) && !empty($sugarFieldMappings['Contacts'])) { |
||
1538 | $contactSugarFields = $this->getBlankFieldsToUpdate($contactSugarFields, $sugarLeadRecord, $sugarFieldMappings['Contacts'], $config); |
||
1539 | } |
||
1540 | if (isset($sugarFieldMappings['Leads']) && !empty($sugarFieldMappings['Leads'])) { |
||
1541 | $leadSugarFields = $this->getBlankFieldsToUpdate($leadSugarFields, $sugarLeadRecord, $sugarFieldMappings['Leads'], $config); |
||
1542 | } |
||
1543 | $this->buildCompositeBody( |
||
1544 | $mauticData, |
||
1545 | $availableFields, |
||
1546 | $isConverted || ('Contacts' == $object) ? $contactSugarFields : $leadSugarFields, |
||
1547 | $isConverted || ('Contacts' == $object) ? 'Contacts' : 'Leads', |
||
1548 | $checkEmailsInSugar[$key], |
||
1549 | $ownerAssignedUserIdByEmail, |
||
1550 | $isConverted ? $sugarLeadRecord['contact_id'] : $sugarLeadRecord['id'] |
||
1551 | ); |
||
1552 | } else { |
||
1553 | // @todo - Should return also deleted contacts from Sugar |
||
1554 | $deletedSugarLeads[] = $sugarLeadRecord['id']; |
||
1555 | if (!empty($sugarLeadRecord['contact_id']) || '' != $sugarLeadRecord['contact_id']) { |
||
1556 | $deletedSugarLeads[] = $sugarLeadRecord['contact_id']; |
||
1557 | } |
||
1558 | } |
||
1559 | unset($checkEmailsInSugar[$key]); |
||
1560 | } |
||
1561 | } |
||
1562 | } |
||
1563 | } |
||
1564 | } |
||
1565 | |||
1566 | return [$checkEmailsInSugar, $deletedSugarLeads]; |
||
1567 | } |
||
1568 | |||
1569 | /** |
||
1570 | * @param $lead |
||
1571 | * |
||
1572 | * @return array |
||
1573 | */ |
||
1574 | public function getSugarLeadId($lead) |
||
1575 | { |
||
1576 | /** @var IntegrationEntityRepository $integrationEntityRepo */ |
||
1577 | $integrationEntityRepo = $this->em->getRepository('MauticPluginBundle:IntegrationEntity'); |
||
1578 | //try searching for lead as this has been changed before in updated done to the plugin |
||
1579 | $result = $integrationEntityRepo->getIntegrationsEntityId('Sugarcrm', null, 'lead', $lead->getId()); |
||
1580 | |||
1581 | return $result; |
||
1582 | } |
||
1583 | |||
1584 | /** |
||
1585 | * @param array $lead |
||
1586 | */ |
||
1587 | protected function getOwnerEmail($lead) |
||
1588 | { |
||
1589 | if (isset($lead['owner_id']) && !empty($lead['owner_id'])) { |
||
1590 | /** @var \Mautic\UserBundle\Entity\User $user */ |
||
1591 | $user = $this->userModel->getEntity($lead['owner_id']); |
||
1592 | |||
1593 | return $user->getEmail(); |
||
1594 | } |
||
1595 | |||
1596 | return null; |
||
1597 | } |
||
1598 | |||
1599 | /** |
||
1600 | * @param $mauticData |
||
1601 | * @param $availableFields |
||
1602 | * @param $object |
||
1603 | * @param $lead |
||
1604 | * @param null $objectId |
||
1605 | */ |
||
1606 | protected function buildCompositeBody(&$mauticData, $availableFields, $fieldsToUpdateInSugarUpdate, $object, $lead, $onwerAssignedUserIdByEmail = null, $objectId = null) |
||
1607 | { |
||
1608 | $body = []; |
||
1609 | if (isset($lead['email']) && !empty($lead['email'])) { |
||
1610 | //update and create (one query) every 200 records |
||
1611 | |||
1612 | foreach ($fieldsToUpdateInSugarUpdate as $sugarField => $mauticField) { |
||
1613 | $required = !empty($availableFields[$object][$sugarField.'__'.$object]['required']); |
||
1614 | if (isset($lead[$mauticField])) { |
||
1615 | if (false !== strpos($lead[$mauticField], '|')) { |
||
1616 | // Transform Mautic Multi Select into SugarCRM/SuiteCRM Multi Select format |
||
1617 | $value = $this->convertMauticToSuiteCrmMultiSelect($lead[$mauticField]); |
||
1618 | } else { |
||
1619 | $value = $lead[$mauticField]; |
||
1620 | } |
||
1621 | $body[] = ['name' => $sugarField, 'value' => $value]; |
||
1622 | } elseif ($required) { |
||
1623 | $value = $this->translator->trans('mautic.integration.form.lead.unknown'); |
||
1624 | $body[] = ['name' => $sugarField, 'value' => $value]; |
||
1625 | } |
||
1626 | } |
||
1627 | |||
1628 | if (!empty($body)) { |
||
1629 | $id = $lead['internal_entity_id'].'-'.$object.(!empty($lead['id']) ? '-'.$lead['id'] : ''); |
||
1630 | |||
1631 | $body[] = ['name' => 'reference_id', 'value' => $id]; |
||
1632 | |||
1633 | if ($objectId) { |
||
1634 | $body[] = ['name' => 'id', 'value' => $objectId]; |
||
1635 | } |
||
1636 | if (isset($onwerAssignedUserIdByEmail) && isset($lead['owner_email']) && isset($onwerAssignedUserIdByEmail[$lead['owner_email']])) { |
||
1637 | $body[] = ['name' => 'assigned_user_id', 'value' => $onwerAssignedUserIdByEmail[$lead['owner_email']]]; |
||
1638 | } |
||
1639 | |||
1640 | // pushd DNC to Sugar CRM |
||
1641 | $this->pushDncToSugar($lead, $body); |
||
1642 | |||
1643 | $mauticData[$object][] = $body; |
||
1644 | } |
||
1645 | } |
||
1646 | } |
||
1647 | |||
1648 | /** |
||
1649 | * @param array $response |
||
1650 | * |
||
1651 | * @return array |
||
1652 | */ |
||
1653 | protected function processCompositeResponse($response) |
||
1654 | { |
||
1655 | $created = 0; |
||
1656 | $errored = 0; |
||
1657 | $updated = 0; |
||
1658 | $object = 'Lead'; |
||
1659 | $persistEntities = []; |
||
1660 | if (is_array($response)) { |
||
1661 | foreach ($response as $item) { |
||
1662 | $contactId = $integrationEntityId = null; |
||
1663 | if (!empty($item['reference_id'])) { |
||
1664 | $reference = explode('-', $item['reference_id']); |
||
1665 | if (3 === count($reference)) { |
||
1666 | list($contactId, $object, $integrationEntityId) = $reference; |
||
1667 | } else { |
||
1668 | list($contactId, $object) = $reference; |
||
1669 | } |
||
1670 | } |
||
1671 | |||
1672 | if (isset($item['ko']) && $item['ko']) { |
||
1673 | $this->logIntegrationError(new \Exception($item['error'])); |
||
1674 | |||
1675 | if ($integrationEntityId) { |
||
1676 | $integrationEntity = $this->em->getReference('MauticPluginBundle:IntegrationEntity', $integrationEntityId); |
||
1677 | $integrationEntity->setLastSyncDate(new \DateTime()); |
||
1678 | |||
1679 | $persistEntities[] = $integrationEntity; |
||
1680 | } elseif ($contactId) { |
||
1681 | $integrationEntity = new IntegrationEntity(); |
||
1682 | $integrationEntity->setDateAdded(new \DateTime()); |
||
1683 | $integrationEntity->setLastSyncDate(new \DateTime()); |
||
1684 | $integrationEntity->setIntegration($this->getName()); |
||
1685 | $integrationEntity->setIntegrationEntity($object); |
||
1686 | $integrationEntity->setInternalEntity('lead-error'); |
||
1687 | $integrationEntity->setInternal(['error' => $item['error']]); |
||
1688 | $integrationEntity->setInternalEntityId($contactId); |
||
1689 | |||
1690 | $persistEntities[] = $integrationEntity; |
||
1691 | ++$errored; |
||
1692 | } |
||
1693 | } elseif (!$item['ko']) { |
||
1694 | if ($item['new']) { |
||
1695 | // New object created |
||
1696 | $integrationEntity = new IntegrationEntity(); |
||
1697 | $integrationEntity->setDateAdded(new \DateTime()); |
||
1698 | $integrationEntity->setLastSyncDate(new \DateTime()); |
||
1699 | $integrationEntity->setIntegration($this->getName()); |
||
1700 | $integrationEntity->setIntegrationEntity($object); |
||
1701 | $integrationEntity->setIntegrationEntityId($item['id']); |
||
1702 | $integrationEntity->setInternalEntity('lead'); |
||
1703 | $integrationEntity->setInternalEntityId($contactId); |
||
1704 | |||
1705 | $persistEntities[] = $integrationEntity; |
||
1706 | ++$created; |
||
1707 | } else { |
||
1708 | // Record was updated |
||
1709 | if ($integrationEntityId) { |
||
1710 | $integrationEntity = $this->em->getReference('MauticPluginBundle:IntegrationEntity', $integrationEntityId); |
||
1711 | $integrationEntity->setLastSyncDate(new \DateTime()); |
||
1712 | } else { |
||
1713 | // Found in Sugarcrm so create a new record for it |
||
1714 | $integrationEntity = new IntegrationEntity(); |
||
1715 | $integrationEntity->setDateAdded(new \DateTime()); |
||
1716 | $integrationEntity->setLastSyncDate(new \DateTime()); |
||
1717 | $integrationEntity->setIntegration($this->getName()); |
||
1718 | $integrationEntity->setIntegrationEntity($object); |
||
1719 | $integrationEntity->setIntegrationEntityId($item['id']); |
||
1720 | $integrationEntity->setInternalEntity('lead'); |
||
1721 | $integrationEntity->setInternalEntityId($contactId); |
||
1722 | } |
||
1723 | |||
1724 | $persistEntities[] = $integrationEntity; |
||
1725 | ++$updated; |
||
1726 | } |
||
1727 | } else { |
||
1728 | $error = 'Unknown status code '.$item['httpStatusCode']; |
||
1729 | $this->logIntegrationError(new \Exception($error.' ('.$item['reference_id'].')')); |
||
1730 | } |
||
1731 | } |
||
1732 | |||
1733 | if ($persistEntities) { |
||
1734 | $this->em->getRepository('MauticPluginBundle:IntegrationEntity')->saveEntities($persistEntities); |
||
1735 | unset($persistEntities); |
||
1736 | $this->em->clear(IntegrationEntity::class); |
||
1737 | } |
||
1738 | } |
||
1739 | |||
1740 | return [$updated, $created, $errored]; |
||
1741 | } |
||
1742 | |||
1743 | /** |
||
1744 | * @param $fieldsToUpdate |
||
1745 | * @param array $objects |
||
1746 | * |
||
1747 | * @return array |
||
1748 | */ |
||
1749 | protected function cleanPriorityFields($fieldsToUpdate, $objects = null) |
||
1750 | { |
||
1751 | if (null === $objects) { |
||
1752 | $objects = ['Leads', 'Contacts']; |
||
1753 | } |
||
1754 | |||
1755 | if (isset($fieldsToUpdate['leadFields'])) { |
||
1756 | // Pass in the whole config |
||
1757 | $fields = $fieldsToUpdate; |
||
1758 | } else { |
||
1759 | $fields = array_flip($fieldsToUpdate); |
||
1760 | } |
||
1761 | |||
1762 | return $this->prepareFieldsForSync($fields, $fieldsToUpdate, $objects); |
||
1763 | } |
||
1764 | |||
1765 | /** |
||
1766 | * @param array $fields |
||
1767 | * @param array $keys |
||
1768 | * @param mixed $object |
||
1769 | * |
||
1770 | * @return array |
||
1771 | */ |
||
1772 | public function prepareFieldsForSync($fields, $keys, $object = null) |
||
1773 | { |
||
1774 | $leadFields = []; |
||
1775 | if (null === $object) { |
||
1776 | $object = 'Lead'; |
||
1777 | } |
||
1778 | |||
1779 | $objects = (!is_array($object)) ? [$object] : $object; |
||
1780 | if (is_string($object) && 'Accounts' === $object) { |
||
1781 | return isset($fields['companyFields']) ? $fields['companyFields'] : $fields; |
||
1782 | } |
||
1783 | |||
1784 | if (isset($fields['leadFields'])) { |
||
1785 | $fields = $fields['leadFields']; |
||
1786 | $keys = array_keys($fields); |
||
1787 | } |
||
1788 | |||
1789 | foreach ($objects as $obj) { |
||
1790 | if (!isset($leadFields[$obj])) { |
||
1791 | $leadFields[$obj] = []; |
||
1792 | } |
||
1793 | |||
1794 | foreach ($keys as $key) { |
||
1795 | if (strpos($key, '__'.$obj)) { |
||
1796 | $newKey = str_replace('__'.$obj, '', $key); |
||
1797 | if ('Id' === $newKey) { |
||
1798 | // Don't map Id for push |
||
1799 | continue; |
||
1800 | } |
||
1801 | |||
1802 | $leadFields[$obj][$newKey] = $fields[$key]; |
||
1803 | } |
||
1804 | } |
||
1805 | } |
||
1806 | |||
1807 | return (is_array($object)) ? $leadFields : $leadFields[$object]; |
||
1808 | } |
||
1809 | |||
1810 | /** |
||
1811 | * @param $config |
||
1812 | * @param null $object |
||
1813 | * @param string $priorityObject |
||
1814 | * |
||
1815 | * @return mixed |
||
1816 | */ |
||
1817 | protected function getPriorityFieldsForMautic($config, $object = null, $priorityObject = 'mautic') |
||
1818 | { |
||
1819 | $fields = parent::getPriorityFieldsForMautic($config, $object, $priorityObject); |
||
1820 | |||
1821 | return ($object && isset($fields[$object])) ? $fields[$object] : $fields; |
||
1822 | } |
||
1823 | |||
1824 | /** |
||
1825 | * @param $fields |
||
1826 | * |
||
1827 | * @return array |
||
1828 | */ |
||
1829 | protected function prepareFieldsForPush($fields) |
||
1830 | { |
||
1831 | $fieldMappings = []; |
||
1832 | $required = []; |
||
1833 | $config = $this->mergeConfigToFeatureSettings(); |
||
1834 | |||
1835 | $contactFields = $this->cleanSugarData($config, array_keys($config['leadFields']), 'Contacts'); |
||
1836 | $leadFields = $this->cleanSugarData($config, array_keys($config['leadFields']), 'Leads'); |
||
1837 | if (!empty($contactFields)) { |
||
1838 | foreach ($fields['Contacts'] as $key => $field) { |
||
1839 | if ($field['required']) { |
||
1840 | $required[$key] = $field; |
||
1841 | } |
||
1842 | } |
||
1843 | $fieldMappings['Contacts']['required'] = [ |
||
1844 | 'fields' => $required, |
||
1845 | ]; |
||
1846 | $fieldMappings['Contacts']['create'] = $contactFields; |
||
1847 | } |
||
1848 | if (!empty($leadFields)) { |
||
1849 | foreach ($fields['Leads'] as $key => $field) { |
||
1850 | if ($field['required']) { |
||
1851 | $required[$key] = $field; |
||
1852 | } |
||
1853 | } |
||
1854 | $fieldMappings['Leads']['required'] = [ |
||
1855 | 'fields' => $required, |
||
1856 | ]; |
||
1857 | $fieldMappings['Leads']['create'] = $leadFields; |
||
1858 | } |
||
1859 | |||
1860 | return $fieldMappings; |
||
1861 | } |
||
1862 | |||
1863 | /** |
||
1864 | * Converts Mautic Multi-Select String into the format used to store Multi-Select values used by SuiteCRM / SugarCRM 6.x. |
||
1865 | * |
||
1866 | * @param string |
||
1867 | * |
||
1868 | * @return string |
||
1869 | */ |
||
1870 | public function convertMauticToSuiteCrmMultiSelect($mauticMultiSelectStringToConvert) |
||
1871 | { |
||
1872 | //$mauticMultiSelectStringToConvert = 'test|enhancedapi|dataservices'; |
||
1873 | $multiSelectArrayValues = explode('|', $mauticMultiSelectStringToConvert); |
||
1874 | $convertedSugarCrmMultiSelectString = ''; |
||
1875 | foreach ($multiSelectArrayValues as $item) { |
||
1876 | $convertedSugarCrmMultiSelectString = $convertedSugarCrmMultiSelectString.'^'.$item.'^'.','; |
||
1877 | } |
||
1878 | |||
1879 | return substr($convertedSugarCrmMultiSelectString, 0, -1); |
||
1880 | } |
||
1881 | |||
1882 | /** |
||
1883 | * Checks if a string contains SuiteCRM / SugarCRM 6.x Multi-Select values. |
||
1884 | * |
||
1885 | * @param string |
||
1886 | * |
||
1887 | * @return bool |
||
1888 | */ |
||
1889 | public function checkIfSugarCrmMultiSelectString($stringToCheck) |
||
1890 | { |
||
1891 | // Regular Express to check SugarCRM/SuiteCRM Multi-Select format below |
||
1892 | // example format: '^choice1^,^choice2^,^choice_3^' |
||
1893 | $regex = '/(\^)(?:([A-Za-z0-9\-\_]+))(\^)/'; |
||
1894 | if (preg_match($regex, $stringToCheck)) { |
||
1895 | return true; |
||
1896 | } else { |
||
1897 | return false; |
||
1898 | } |
||
1899 | } |
||
1900 | |||
1901 | /** |
||
1902 | * Converts a SuiteCRM / SugarCRM 6.x Multi-Select String into the format used to store Multi-Select values used by Mautic. |
||
1903 | * |
||
1904 | * @param string |
||
1905 | * |
||
1906 | * @return string |
||
1907 | */ |
||
1908 | public function convertSuiteCrmToMauticMultiSelect($suiteCrmMultiSelectStringToConvert) |
||
1909 | { |
||
1910 | // Mautic Multi Select format - 'choice1|choice2|choice_3' |
||
1911 | $regexString = '/(\^)(?:([A-Za-z0-9\-\_]+))(\^)/'; |
||
1912 | preg_match_all($regexString, $suiteCrmMultiSelectStringToConvert, $matches, PREG_SET_ORDER, 0); |
||
1913 | $convertedString = ''; |
||
1914 | foreach ($matches as $innerArray) { |
||
1915 | $convertedString = $convertedString.$innerArray[2].'|'; |
||
1916 | } |
||
1917 | |||
1918 | return substr($convertedString, 0, -1); |
||
1919 | } |
||
1920 | } |
||
1921 |