Issues (3627)

Integration/SugarcrmIntegration.php (1 issue)

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
The method getIdBySugarEmail() does not exist on MauticPlugin\MauticCrmBundle\Api\CrmApi. It seems like you code against a sub-type of MauticPlugin\MauticCrmBundle\Api\CrmApi such as MauticPlugin\MauticCrmBundle\Api\SugarcrmApi. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

1195
                    $sugarOwnerId = $this->getApiHelper()->/** @scrutinizer ignore-call */ getIdBySugarEmail(['emails' => [$lead->getOwner()->getEmail()]]);
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