Completed
Push — master ( 93694a...685540 )
by
unknown
09:24
created

ForecastOfOpportunities::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 15
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 15
rs 9.4286
cc 1
eloc 13
nc 1
nop 6
1
<?php
2
3
namespace OroCRM\Bundle\SalesBundle\Provider;
4
5
use Symfony\Bridge\Doctrine\RegistryInterface;
6
use Symfony\Component\Translation\TranslatorInterface;
7
use Symfony\Component\Security\Core\User\UserInterface;
8
9
use Oro\Bundle\DashboardBundle\Model\WidgetOptionBag;
10
use Oro\Bundle\LocaleBundle\Formatter\DateTimeFormatter;
11
use Oro\Bundle\LocaleBundle\Formatter\NumberFormatter;
12
use Oro\Bundle\SecurityBundle\ORM\Walker\AclHelper;
13
use Oro\Bundle\SecurityBundle\SecurityFacade;
14
use Oro\Bundle\UserBundle\Entity\User;
15
16
/**
17
 * Class ForecastOfOpportunities
18
 * @package OroCRM\Bundle\SalesBundle\Provider
19
 */
20
class ForecastOfOpportunities
21
{
22
    /** @var RegistryInterface */
23
    protected $doctrine;
24
25
    /** @var NumberFormatter */
26
    protected $numberFormatter;
27
28
    /** @var DateTimeFormatter */
29
    protected $dateTimeFormatter;
30
31
    /** @var AclHelper */
32
    protected $aclHelper;
33
34
    /** @var TranslatorInterface */
35
    protected $translator;
36
37
    /** @var  array */
38
    protected $ownersValues;
39
40
    /** @var SecurityFacade */
41
    protected $securityFacade;
42
43
    /** @var User */
44
    protected $currentUser;
45
46
    /**
47
     * @param RegistryInterface   $doctrine
48
     * @param NumberFormatter     $numberFormatter
49
     * @param DateTimeFormatter   $dateTimeFormatter
50
     * @param AclHelper           $aclHelper
51
     * @param TranslatorInterface $translator
52
     * @param SecurityFacade      $securityFacade
53
     */
54
    public function __construct(
55
        RegistryInterface $doctrine,
56
        NumberFormatter $numberFormatter,
57
        DateTimeFormatter $dateTimeFormatter,
58
        AclHelper $aclHelper,
59
        TranslatorInterface $translator,
60
        SecurityFacade $securityFacade
61
    ) {
62
        $this->doctrine          = $doctrine;
63
        $this->numberFormatter   = $numberFormatter;
64
        $this->dateTimeFormatter = $dateTimeFormatter;
65
        $this->aclHelper         = $aclHelper;
66
        $this->translator        = $translator;
67
        $this->securityFacade    = $securityFacade;
68
    }
69
70
    /**
71
     * @param WidgetOptionBag $widgetOptions
72
     * @param string          $getterName
73
     * @param string          $dataType
74
     * @param bool            $lessIsBetter
75
     * @return array
76
     */
77
    public function getForecastOfOpportunitiesValues(
78
        WidgetOptionBag $widgetOptions,
79
        $getterName,
80
        $dataType,
81
        $lessIsBetter = false
82
    ) {
83
        $lessIsBetter     = (bool)$lessIsBetter;
84
        $result           = [];
85
86
        /** @var WidgetOptionBag $widgetOptions */
87
        $widgetOptions = $this->prepareDefaultOptions($widgetOptions);
88
89
        $ownerIds         = $this->getOwnerIds($widgetOptions);
90
        $value            = $this->{$getterName}($ownerIds);
91
        $result['value']  = $this->formatValue($value, $dataType);
92
        $compareToDate = $widgetOptions->get('compareToDate');
93
94
        if (isset($compareToDate['useDate']) && $compareToDate['useDate']) {
95
            if (empty($compareToDate['date'])) {
96
                $compareToDate['date'] = new \DateTime();
97
                $compareToDate['date']->modify('-1 month');
98
                $compareToDate['date']->setTime(0, 0, 0);
99
            }
100
            $pastResult = $this->{$getterName}($ownerIds, $compareToDate['date']);
101
            $result['deviation'] = $this->translator
102
                ->trans('orocrm.sales.dashboard.forecast_of_opportunities.no_changes');
103
            $result = $this->prepareData($dataType, $lessIsBetter, $pastResult, $value - $pastResult, $result);
104
            $result['previousRange'] = $this->dateTimeFormatter->formatDate($compareToDate['date']);
105
        }
106
107
        return $result;
108
    }
109
110
    /**
111
     * Prepare Default Options for User and business Units
112
     *
113
     * @param WidgetOptionBag $widgetOptions
114
     *
115
     * @return bool
116
     */
117
    protected function prepareDefaultOptions($widgetOptions)
118
    {
119
        $owners = $widgetOptions->get('owners');
120
        $businessUnits = $widgetOptions->get('businessUnits');
121
122
        if (!$owners && !$businessUnits) {
123
            $user = $this->getCurrentUser();
124
            if ($user instanceof User) {
125
                $businessUnits = $user->getBusinessUnits();
126
                $businessUnitsData = [];
127
                foreach ($businessUnits as $businessUnit) {
128
                    if (is_object($businessUnit)) {
129
                        $businessUnitsData[] = $businessUnit;
130
                    }
131
                }
132
                $options = ['owners' => [$user], 'businessUnits' => $businessUnitsData];
133
                $widgetOptions = new WidgetOptionBag($options);
134
            }
135
        }
136
137
        return $widgetOptions;
138
    }
139
140
    /**
141
     * @param array $ownerIds
142
     * @param null $compareToDate
143
     * @return int
144
     */
145
    protected function getInProgressValues($ownerIds, $compareToDate = null)
146
    {
147
        $values = $this->getOwnersValues($ownerIds, $compareToDate);
148
149
        return $values && isset($values['inProgressCount']) ? $values['inProgressCount'] : 0;
150
    }
151
152
    /**
153
     * @param array $ownerIds
154
     * @param null $compareToDate
155
     * @return int
156
     */
157
    protected function getTotalForecastValues($ownerIds, $compareToDate = null)
158
    {
159
        $values = $this->getOwnersValues($ownerIds, $compareToDate);
160
161
        return $values && isset($values['budgetAmount']) ? $values['budgetAmount'] : 0;
162
    }
163
164
    /**
165
     * @param array $ownerIds
166
     * @param null $compareToDate
167
     * @return int
168
     */
169
    protected function getWeightedForecastValues($ownerIds, $compareToDate = null)
170
    {
171
        $values = $this->getOwnersValues($ownerIds, $compareToDate);
172
173
        return $values && isset($values['weightedForecast']) ? $values['weightedForecast'] : 0;
174
    }
175
176
    /**
177
     * @param array $ownerIds
178
     * @param \DateTime|string|int $date
179
     * @return mixed
180
     */
181
    protected function getOwnersValues(array $ownerIds, $date)
182
    {
183
        $key = sha1(implode('_', $ownerIds) . $this->dateTimeFormatter->formatDate($date));
184
        if (!isset($this->ownersValues[$key])) {
185
            $this->ownersValues[$key] = $this->doctrine
186
                ->getRepository('OroCRMSalesBundle:Opportunity')
187
                ->getForecastOfOpporunitiesData($ownerIds, $date, $this->aclHelper);
188
        }
189
190
        return $this->ownersValues[$key];
191
    }
192
193
    /**
194
     * @param mixed  $value
195
     * @param string $type
196
     * @param bool   $isDeviant
197
     *
198
     * @return string
199
     */
200
    protected function formatValue($value, $type = '', $isDeviant = false)
201
    {
202
        $sign = null;
203
204
        if ($isDeviant && $value !== 0) {
205
            $sign  = $value > 0 ? '+' : '&minus;';
206
            $value = abs($value);
207
        }
208
        switch ($type) {
209
            case 'currency':
210
                $value = $this->numberFormatter->formatCurrency($value);
211
                break;
212
            case 'percent':
213
                if ($isDeviant) {
214
                    $value = round(($value) * 100, 0) / 100;
215
                } else {
216
                    $value = round(($value) * 100, 2) / 100;
217
                }
218
219
                $value = $this->numberFormatter->formatPercent($value);
220
                break;
221
            default:
222
                $value = $this->numberFormatter->formatDecimal($value);
223
        }
224
225
        return $isDeviant && !is_null($sign) ? sprintf('%s%s', $sign, $value) : $value;
226
    }
227
228
    /**
229
     * @param $dataType
230
     * @param $lessIsBetter
231
     * @param $pastResult
232
     * @param $deviation
233
     * @param $result
234
     *
235
     * @return array
236
     */
237
    protected function prepareData($dataType, $lessIsBetter, $pastResult, $deviation, $result)
238
    {
239
        if ($pastResult != 0 && $dataType !== 'percent') {
240
            if ($deviation != 0) {
241
                $deviationPercent = $deviation / $pastResult;
242
                $result['deviation'] = sprintf(
243
                    '%s (%s)',
244
                    $this->formatValue($deviation, $dataType, true),
245
                    $this->formatValue($deviationPercent, 'percent', true)
246
                );
247 View Code Duplication
                if (!$lessIsBetter) {
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...
248
                    $result['isPositive'] = $deviation > 0;
249
                } else {
250
                    $result['isPositive'] = !($deviation > 0);
251
                }
252
            }
253
        } else {
254
            if (round(($deviation) * 100, 0) != 0) {
255
                $result['deviation'] = $this->formatValue($deviation, $dataType, true);
256 View Code Duplication
                if (!$lessIsBetter) {
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...
257
                    $result['isPositive'] = $deviation > 0;
258
                } else {
259
                    $result['isPositive'] = !($deviation > 0);
260
                }
261
            }
262
        }
263
264
        return $result;
265
    }
266
267
    /**
268
     * @param WidgetOptionBag $widgetOptions
269
     *
270
     * @return array
271
     */
272
    protected function getOwnerIds(WidgetOptionBag $widgetOptions)
273
    {
274
        $owners = $widgetOptions->get('owners');
275
        $owners = is_array($owners) ? $owners : [$owners];
276
277
        $ownerIds = [];
278
        foreach ($owners as $owner) {
279
            if (is_object($owner)) {
280
                $ownerIds[] = $owner->getId();
281
            }
282
        }
283
284
        $businessUnitIds = $this->getBusinessUnitsIds($widgetOptions);
285
286
        if (!empty($businessUnitIds)) {
287
            //need to load from repository, because it returns unserialized object without users from widget options
288
            $businessUnits = $this->doctrine
0 ignored issues
show
Bug introduced by
The method findById() does not exist on Doctrine\Common\Persistence\ObjectRepository. Did you maybe mean findBy()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
289
                ->getRepository('OroOrganizationBundle:BusinessUnit')
290
                ->findById($businessUnitIds);
291
292
            foreach ($businessUnits as $businessUnit) {
293
                $users = $businessUnit->getUsers();
294
                foreach ($users as $user) {
295
                    $ownerIds[] = $user->getId();
296
                }
297
            }
298
299
            $ownerIds = array_unique($ownerIds);
300
        }
301
302
        return $ownerIds;
303
    }
304
305
    /**
306
     * @param WidgetOptionBag $widgetOptions
307
     *
308
     * @return array
309
     */
310
    protected function getBusinessUnitsIds(WidgetOptionBag $widgetOptions)
311
    {
312
        $businessUnits = $widgetOptions->get('businessUnits');
313
314
        $businessUnits = is_array($businessUnits) ? $businessUnits : [$businessUnits];
315
316
        $businessUnitIds = [];
317
318
        foreach ($businessUnits as $businessUnit) {
319
            if (is_object($businessUnit)) {
320
                $businessUnitIds[] = $businessUnit->getId();
321
            }
322
        }
323
324
        return $businessUnitIds;
325
    }
326
327
    /**
328
     * @return UserInterface
329
     */
330
    protected function getCurrentUser()
331
    {
332
        if (!$this->currentUser) {
333
            $user = $this->securityFacade->getLoggedUser();
334
            if ($user instanceof UserInterface) {
335
                $this->currentUser = $user;
336
            }
337
        }
338
339
        return $this->currentUser;
340
    }
341
}
342