Completed
Push — master ( d7a3f6...44e45d )
by
unknown
10:44
created

LoadLeadsData::loadSalesFlows()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 55
Code Lines 35

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 55
rs 9.078
c 0
b 0
f 0
cc 4
eloc 35
nc 4
nop 1

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace OroCRM\Bundle\ReportBundle\Tests\Functional\DataFixtures;
4
5
use Doctrine\Common\Collections\Collection;
6
use Doctrine\Common\DataFixtures\AbstractFixture;
7
use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
8
use Doctrine\Common\Persistence\ObjectManager;
9
use Doctrine\ORM\EntityManager;
10
11
use Oro\Bundle\CurrencyBundle\Entity\MultiCurrency;
12
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
13
use Symfony\Component\DependencyInjection\ContainerInterface;
14
15
use Oro\Bundle\AddressBundle\Entity\Country;
16
use Oro\Bundle\AddressBundle\Entity\Region;
17
use Oro\Bundle\EntityConfigBundle\Config\ConfigManager;
18
use Oro\Bundle\EntityExtendBundle\Entity\AbstractEnumValue;
19
use Oro\Bundle\EntityExtendBundle\Tools\ExtendHelper;
20
use Oro\Bundle\OrganizationBundle\Entity\Organization;
21
use Oro\Bundle\SecurityBundle\Authentication\Token\UsernamePasswordOrganizationToken;
22
use Oro\Bundle\UserBundle\Entity\User;
23
use Oro\Bundle\WorkflowBundle\Entity\WorkflowItem;
24
use Oro\Bundle\WorkflowBundle\Model\WorkflowManager;
25
26
use OroCRM\Bundle\ChannelBundle\Builder\BuilderFactory;
27
use OroCRM\Bundle\ChannelBundle\Entity\Channel;
28
use OroCRM\Bundle\SalesBundle\Entity\Lead;
29
use OroCRM\Bundle\SalesBundle\Entity\LeadPhone;
30
use OroCRM\Bundle\SalesBundle\Entity\LeadEmail;
31
use OroCRM\Bundle\SalesBundle\Entity\LeadAddress;
32
use OroCRM\Bundle\SalesBundle\Entity\Opportunity;
33
use OroCRM\Bundle\SalesBundle\Migrations\Data\ORM\DefaultChannelData;
34
35
class LoadLeadsData extends AbstractFixture implements ContainerAwareInterface, OrderedFixtureInterface
36
{
37
    const FLUSH_MAX = 50;
38
39
    /** @var ContainerInterface */
40
    protected $container;
41
42
    /** @var User[] */
43
    protected $users;
44
45
    /** @var Country[] */
46
    protected $countries;
47
48
    /** @var WorkflowManager */
49
    protected $workflowManager;
50
51
    /** @var  EntityManager */
52
    protected $em;
53
54
    /** @var Organization */
55
    protected $organization;
56
57
    /** @var BuilderFactory */
58
    protected $channelBuilderFactory;
59
60
    /** @var Channel */
61
    protected $channel;
62
63
    /** @var AbstractEnumValue[] */
64
    protected $sources;
65
66
67
    /**
68
     * {@inheritDoc}
69
     */
70
    public function setContainer(ContainerInterface $container = null)
71
    {
72
        $this->container             = $container;
73
        $this->workflowManager       = $container->get('oro_workflow.manager');
0 ignored issues
show
Bug introduced by
It seems like $container is not always an object, but can also be of type null. Maybe add an additional type check?

If a variable is not always an object, we recommend to add an additional type check to ensure your method call is safe:

function someFunction(A $objectMaybe = null)
{
    if ($objectMaybe instanceof A) {
        $objectMaybe->doSomething();
    }
}
Loading history...
74
        $this->channelBuilderFactory = $container->get('orocrm_channel.builder.factory');
75
    }
76
77
    /**
78
     * {@inheritDoc}
79
     */
80
    public function load(ObjectManager $manager)
81
    {
82
        $this->organization = $manager->getRepository('OroOrganizationBundle:Organization')->getFirst();
83
        $this->initSupportingEntities($manager);
84
        $this->loadLeads($manager);
85
    }
86
87
    protected function initSupportingEntities(ObjectManager $manager = null)
88
    {
89
        if ($manager) {
90
            $this->em = $manager;
91
        }
92
93
        $this->users     = $this->em->getRepository('OroUserBundle:User')->findAll();
94
        $this->countries = $this->em->getRepository('OroAddressBundle:Country')->findAll();
95
96
        $className     = ExtendHelper::buildEnumValueClassName('lead_source');
97
        $enumRepo      = $manager->getRepository($className);
0 ignored issues
show
Bug introduced by
It seems like $manager is not always an object, but can also be of type null. Maybe add an additional type check?

If a variable is not always an object, we recommend to add an additional type check to ensure your method call is safe:

function someFunction(A $objectMaybe = null)
{
    if ($objectMaybe instanceof A) {
        $objectMaybe->doSomething();
    }
}
Loading history...
98
        $this->sources = $enumRepo->findAll();
99
100
        $this->channel = $this
101
            ->channelBuilderFactory
102
            ->createBuilder()
103
            ->setChannelType(DefaultChannelData::B2B_CHANNEL_TYPE)
104
            ->setStatus(Channel::STATUS_ACTIVE)
105
            ->setEntities()
106
            ->getChannel();
107
108
        $manager->persist($this->channel);
109
        $manager->flush($this->channel);
110
    }
111
112
    public function loadLeads(ObjectManager $manager)
113
    {
114
        $handle = fopen(__DIR__ . DIRECTORY_SEPARATOR . 'dictionaries' . DIRECTORY_SEPARATOR . "leads.csv", "r");
115 View Code Duplication
        if ($handle) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
116
            $headers = [];
117
            if (($data = fgetcsv($handle, 1000, ",")) !== false) {
118
                //read headers
119
                $headers = $data;
120
            }
121
            $randomUser = count($this->users) - 1;
122
            $i          = 0;
123
            while (($data = fgetcsv($handle, 1000, ",")) !== false) {
124
                $user = $this->users[mt_rand(0, $randomUser)];
125
                $this->setSecurityContext($user);
126
127
                $data = array_combine($headers, array_values($data));
128
129
                $lead = $this->createLead($manager, $data, $user);
130
                $this->em->persist($lead);
131
132
                $this->loadSalesFlows($lead);
133
134
                $i++;
135
                if ($i % self::FLUSH_MAX == 0) {
136
                    $this->em->flush();
137
                }
138
            }
139
140
            $this->em->flush();
141
            fclose($handle);
142
        }
143
    }
144
145
    /**
146
     * @param Lead $lead
147
     */
148
    protected function loadSalesFlows(Lead $lead)
149
    {
150
        $leadWorkflowItem = $this->workflowManager->startWorkflow(
151
            'b2b_flow_lead',
152
            $lead,
153
            'qualify',
154
            [
155
                'opportunity_name' => $lead->getName(),
156
                'company_name' => $lead->getCompanyName(),
157
            ]
158
        );
159
        //@TODO change test according to CRM-6344
160
        if ($this->getRandomBoolean()) {
161
            /** @var Opportunity $opportunity */
162
            $opportunity   = $leadWorkflowItem->getResult()->get('opportunity');
163
            $budgetAmount = MultiCurrency::create(mt_rand(10, 10000), 'USD');
164
            $closeRevenue = MultiCurrency::create(mt_rand(10, 10000), 'USD');
165
            $salesFlowItem = $this->workflowManager->startWorkflow(
166
                'opportunity_flow',
167
                $opportunity,
168
                '__start__',
169
                [
170
                    'budget_amount'     => $budgetAmount,
171
                    'customer_need'     => mt_rand(10, 10000),
172
                    'proposed_solution' => mt_rand(10, 10000),
173
                    'probability'       => round(mt_rand(50, 85) / 100.00, 2)
174
                ]
175
            );
176
177
            if ($this->getRandomBoolean()) {
178
                if ($this->getRandomBoolean()) {
179
                    $this->transit(
180
                        $this->workflowManager,
181
                        $salesFlowItem,
182
                        'close_won',
183
                        [
184
                            'close_revenue' => $closeRevenue,
185
                            'close_date'    => new \DateTime('now'),
186
                        ]
187
                    );
188
                } else {
189
                    $this->transit(
190
                        $this->workflowManager,
191
                        $salesFlowItem,
192
                        'close_lost',
193
                        [
194
                            'close_reason_name' => 'cancelled',
195
                            'close_revenue'     => $closeRevenue,
196
                            'close_date'        => new \DateTime('now'),
197
                        ]
198
                    );
199
                }
200
            }
201
        }
202
    }
203
204
    /**
205
     * @return bool
206
     */
207
    protected function getRandomBoolean()
208
    {
209
        return (bool)mt_rand(0, 1);
210
    }
211
212
    /**
213
     * @param User $user
214
     */
215 View Code Duplication
    protected function setSecurityContext($user)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
216
    {
217
        $securityContext = $this->container->get('security.context');
218
        $token           = new UsernamePasswordOrganizationToken($user, $user->getUsername(
219
        ), 'main', $this->organization);
220
        $securityContext->setToken($token);
221
    }
222
223
    /**
224
     * @param ObjectManager $manager
225
     * @param  array $data
226
     * @param User $user
227
     *
228
     * @return Lead
229
     */
230
    protected function createLead(ObjectManager $manager, array $data, $user)
231
    {
232
        $lead = new Lead();
233
        
234
        $className = ExtendHelper::buildEnumValueClassName(Lead::INTERNAL_STATUS_CODE);
235
        $defaultStatus = $manager->getRepository($className)->find(ExtendHelper::buildEnumValueId('new'));
236
        
237
        $lead->setStatus($defaultStatus);
238
        $lead->setName($data['Company']);
239
        $lead->setFirstName($data['GivenName']);
240
        $lead->setLastName($data['Surname']);
241
242
        $leadEmail = new LeadEmail($data['EmailAddress']);
243
        $leadEmail->setPrimary(true);
244
        $lead->addEmail($leadEmail);
245
246
        $leadPhone = new LeadPhone($data['TelephoneNumber']);
247
        $leadPhone->setPrimary(true);
248
        $lead->addPhone($leadPhone);
249
250
        $lead->setCompanyName($data['Company']);
251
        $lead->setOwner($user);
252
        $lead->setDataChannel($this->channel);
253
        /** @var LeadAddress $address */
254
        $address = new LeadAddress();
255
        $address->setLabel('Primary Address');
256
        $address->setCity($data['City']);
257
        $address->setStreet($data['StreetAddress']);
258
        $address->setPostalCode($data['ZipCode']);
259
        $address->setFirstName($data['GivenName']);
260
        $address->setLastName($data['Surname']);
261
262
        $isoCode = $data['Country'];
263
        $country = array_filter(
264
            $this->countries,
265
            function (Country $a) use ($isoCode) {
266
                return $a->getIso2Code() == $isoCode;
267
            }
268
        );
269
270
        $country = array_values($country);
271
        /** @var Country $country */
272
        $country = $country[0];
273
274
        $idRegion = $data['State'];
275
        /** @var Collection $regions */
276
        $regions = $country->getRegions();
277
278
        $region = $regions->filter(
279
            function (Region $a) use ($idRegion) {
280
                return $a->getCode() == $idRegion;
281
            }
282
        );
283
284
        $address->setCountry($country);
285
        if (!$region->isEmpty()) {
286
            $address->setRegion($region->first());
287
        }
288
289
        $lead->addAddress($address);
290
291
        $countSources = count($this->sources) - 1;
292
        $source       = $this->sources[mt_rand(0, $countSources)];
293
        $lead->setSource($source);
294
295
        return $lead;
296
    }
297
298
    /**
299
     * @param WorkflowManager $workflowManager
300
     * @param WorkflowItem    $workflowItem
301
     * @param string          $transition
302
     * @param array           $data
303
     */
304
    protected function transit($workflowManager, $workflowItem, $transition, array $data)
305
    {
306
        foreach ($data as $key => $value) {
307
            $workflowItem->getData()->set($key, $value);
308
        }
309
310
        $workflow = $workflowManager->getWorkflow($workflowItem);
311
312
        $workflow->transit($workflowItem, $transition);
313
        $workflowItem->setUpdated();
314
    }
315
316
    public function getOrder()
317
    {
318
        return 300;
319
    }
320
}
321