Completed
Push — master ( 584969...3f5763 )
by
unknown
11:30
created

ForecastOfOpportunities::getBusinessUnitsIds()   A

Complexity

Conditions 4
Paths 6

Size

Total Lines 16
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 16
rs 9.2
c 0
b 0
f 0
cc 4
eloc 8
nc 6
nop 1
1
<?php
2
3
namespace OroCRM\Bundle\SalesBundle\Provider;
4
5
use Symfony\Bridge\Doctrine\RegistryInterface;
6
use Symfony\Component\Translation\TranslatorInterface;
7
8
use Oro\Bundle\DashboardBundle\Model\WidgetOptionBag;
9
use Oro\Bundle\LocaleBundle\Formatter\DateTimeFormatter;
10
use Oro\Bundle\LocaleBundle\Formatter\NumberFormatter;
11
use Oro\Bundle\SecurityBundle\ORM\Walker\AclHelper;
12
use Oro\Component\DoctrineUtils\ORM\QueryUtils;
13
use Oro\Bundle\DashboardBundle\Helper\DateHelper;
14
use Oro\Bundle\UserBundle\Dashboard\OwnerHelper;
15
16
/**
17
 * Class ForecastOfOpportunities
18
 * @package OroCRM\Bundle\SalesBundle\Provider
19
 * @SuppressWarnings(PHPMD.ExcessiveClassComplexity)
20
 */
21
class ForecastOfOpportunities
22
{
23
    /** @var RegistryInterface */
24
    protected $doctrine;
25
26
    /** @var NumberFormatter */
27
    protected $numberFormatter;
28
29
    /** @var DateTimeFormatter */
30
    protected $dateTimeFormatter;
31
32
    /** @var AclHelper */
33
    protected $aclHelper;
34
35
    /** @var TranslatorInterface */
36
    protected $translator;
37
38
    /** @var DateHelper */
39
    protected $dateHelper;
40
41
    /** @var  array */
42
    protected $ownersValues;
43
44
    /**
45
     * @param RegistryInterface   $doctrine
46
     * @param NumberFormatter     $numberFormatter
47
     * @param DateTimeFormatter   $dateTimeFormatter
48
     * @param AclHelper           $aclHelper
49
     * @param TranslatorInterface $translator
50
     * @param DateHelper          $dateHelper
51
     * @param OwnerHelper         $ownerHelper
52
     */
53
    public function __construct(
54
        RegistryInterface $doctrine,
55
        NumberFormatter $numberFormatter,
56
        DateTimeFormatter $dateTimeFormatter,
57
        AclHelper $aclHelper,
58
        TranslatorInterface $translator,
59
        DateHelper $dateHelper,
60
        OwnerHelper $ownerHelper
61
    ) {
62
        $this->doctrine          = $doctrine;
63
        $this->numberFormatter   = $numberFormatter;
64
        $this->dateTimeFormatter = $dateTimeFormatter;
65
        $this->aclHelper         = $aclHelper;
66
        $this->translator        = $translator;
67
        $this->dateHelper        = $dateHelper;
68
        $this->ownerHelper       = $ownerHelper;
0 ignored issues
show
Bug introduced by
The property ownerHelper does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
69
    }
70
71
    /**
72
     * @param WidgetOptionBag $widgetOptions
73
     * @param string          $getterName
74
     * @param string          $dataType
75
     * @param bool            $lessIsBetter
76
     *
77
     * @return array
78
     */
79
    public function getForecastOfOpportunitiesValues(
80
        WidgetOptionBag $widgetOptions,
81
        $getterName,
82
        $dataType,
83
        $lessIsBetter = false
84
    ) {
85
        $lessIsBetter = (bool)$lessIsBetter;
86
        $result       = [];
87
88
        $ownerIds = $this->ownerHelper->getOwnerIds($widgetOptions);
89
        $compareToDate   = $widgetOptions->get('compareToDate');
90
        $usePrevious     = !empty($compareToDate['useDate']);
91
        $dateData        = $this->prepareDateRange($widgetOptions->get('dateRange'), $usePrevious);
92
        $value           = $this->{$getterName}($ownerIds, $dateData['start'], $dateData['end']);
93
        $result['value'] = $this->formatValue($value, $dataType);
94
        if (!empty($dateData['prev_start'])
95
            && !empty($dateData['prev_end'])
96
            && !empty($dateData['prev_moment'])
97
        ) {
98
            $pastResult              = $this->{$getterName}(
99
                $ownerIds,
100
                $dateData['prev_start'],
101
                $dateData['prev_end'],
102
                $dateData['prev_moment']
103
            );
104
            $result['deviation']     = $this->translator
105
                ->trans('orocrm.sales.dashboard.forecast_of_opportunities.no_changes');
106
            $result                  = $this->prepareData(
107
                $dataType,
108
                $lessIsBetter,
109
                $pastResult,
110
                $value - $pastResult,
111
                $result
112
            );
113
            $result['previousRange'] = $this->dateTimeFormatter->formatDate($dateData['prev_moment']);
114
        }
115
116
        return $result;
117
    }
118
119
    /**
120
     * @param array                $ownerIds
121
     * @param \DateTime            $start
122
     * @param \DateTime            $end
123
     * @param \DateTime|string|int $compareToDate
124
     *
125
     * @return int
126
     */
127
    protected function getInProgressValues($ownerIds, $start = null, $end = null, $compareToDate = null)
128
    {
129
        $values = $this->getOwnersValues($ownerIds, $start, $end, $compareToDate);
130
131
        return $values && isset($values['inProgressCount']) ? $values['inProgressCount'] : 0;
132
    }
133
134
    /**
135
     * @param array                $ownerIds
136
     * @param \DateTime            $start
137
     * @param \DateTime            $end
138
     * @param \DateTime|string|int $compareToDate
139
     *
140
     * @return int
141
     */
142
    protected function getTotalForecastValues($ownerIds, $start = null, $end = null, $compareToDate = null)
143
    {
144
        $values = $this->getOwnersValues($ownerIds, $start, $end, $compareToDate);
145
146
        return $values && isset($values['budgetAmount']) ? $values['budgetAmount'] : 0;
147
    }
148
149
    /**
150
     * @param array                $ownerIds
151
     * @param \DateTime            $start
152
     * @param \DateTime            $end
153
     * @param \DateTime|string|int $compareToDate
154
     *
155
     * @return int
156
     */
157
    protected function getWeightedForecastValues($ownerIds, $start = null, $end = null, $compareToDate = null)
158
    {
159
        $values = $this->getOwnersValues($ownerIds, $start, $end, $compareToDate);
160
161
        return $values && isset($values['weightedForecast']) ? $values['weightedForecast'] : 0;
162
    }
163
164
    /**
165
     * @param array                $ownerIds
166
     * @param \DateTime            $start
167
     * @param \DateTime            $end
168
     * @param \DateTime|string|int $date
169
     *
170
     * @return mixed
171
     */
172
    protected function getOwnersValues(array $ownerIds, $start = null, $end = null, $date = null)
173
    {
174
        $dateKey      = $date ? $this->dateTimeFormatter->formatDate($date) : '';
175
        $key          = sha1(
176
            implode('_', $ownerIds) . 'date' . $dateKey . 'start' . (string)$start . 'end' . (string)$end
177
        );
178
        if (!isset($this->ownersValues[$key])) {
179
            $this->ownersValues[$key] = $this->doctrine
180
                ->getRepository('OroCRMSalesBundle:Opportunity')
181
                ->getForecastOfOpportunitiesData($ownerIds, $date, $this->aclHelper, $start, $end);
182
        }
183
184
        return $this->ownersValues[$key];
185
    }
186
187
    /**
188
     * @param mixed  $value
189
     * @param string $type
190
     * @param bool   $isDeviant
191
     *
192
     * @return string
193
     */
194
    protected function formatValue($value, $type = '', $isDeviant = false)
195
    {
196
        $sign      = null;
197
        $precision = 2;
198
199
        if ($isDeviant) {
200
            if ($value !== 0) {
201
                $sign  = $value > 0 ? '+' : '&minus;';
202
                $value = abs($value);
203
            }
204
            $precision = 0;
205
        }
206
207
        if ($type === 'currency') {
208
            $formattedValue = $this->numberFormatter->formatCurrency($value);
209
        } elseif ($type === 'percent') {
210
            $value          = round(($value) * 100, $precision) / 100;
211
            $formattedValue = $this->numberFormatter->formatPercent($value);
212
        } else {
213
            $formattedValue = $this->numberFormatter->formatDecimal($value);
214
        }
215
216
        if ($sign) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $sign of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
217
            $formattedValue = sprintf('%s%s', $sign, $formattedValue);
218
        }
219
220
        return $formattedValue;
221
    }
222
223
    /**
224
     * @param $dataType
225
     * @param $lessIsBetter
226
     * @param $pastResult
227
     * @param $deviation
228
     * @param $result
229
     *
230
     * @return array
231
     */
232
    protected function prepareData($dataType, $lessIsBetter, $pastResult, $deviation, $result)
233
    {
234
        if ($pastResult != 0 && $dataType !== 'percent') {
235
            if ($deviation != 0) {
236
                $deviationPercent     = $deviation / $pastResult;
237
                $result['deviation']  = sprintf(
238
                    '%s (%s)',
239
                    $this->formatValue($deviation, $dataType, true),
240
                    $this->formatValue($deviationPercent, 'percent', true)
241
                );
242
                $result['isPositive'] = $this->isPositive($lessIsBetter, $deviation);
243
            }
244
        } else {
245
            if (round(($deviation) * 100, 0) != 0) {
246
                $result['deviation']  = $this->formatValue($deviation, $dataType, true);
247
                $result['isPositive'] = $this->isPositive($lessIsBetter, $deviation);
248
            }
249
        }
250
251
        return $result;
252
    }
253
254
    /**
255
     * Get is positive value
256
     *
257
     * @param $lessIsBetter
258
     * @param $deviation
259
     *
260
     * @return bool
261
     */
262
    protected function isPositive($lessIsBetter, $deviation)
263
    {
264
        if (!$lessIsBetter) {
265
            $result = $deviation > 0;
266
        } else {
267
            $result = !($deviation > 0);
268
        }
269
270
        return $result;
271
    }
272
273
    /**
274
     * @param array $dateRange
275
     * @param bool  $usePrevious
276
     *
277
     * @return array
278
     */
279
    protected function prepareDateRange(array $dateRange, $usePrevious)
280
    {
281
        /** @var \DateTime $start */
282
        /** @var \DateTime $end */
283
        $start = $dateRange['start'];
284
        $end   = $dateRange['end'];
285
        $data  = [
286
            'start' => $start ? $start->format('Y-m-d') : null,
287
            'end'   => $end ? $end->format('Y-m-d') : null
288
        ];
289
        if ($usePrevious
290
            && !empty($dateRange['prev_start'])
291
            && !empty($dateRange['prev_end'])
292
        ) {
293
            /** @var \DateTime $prevStart */
294
            /** @var \DateTime $prevEnd */
295
            $prevStart = $dateRange['prev_start'];
296
            $prevEnd   = $dateRange['prev_end'];
297
            // current moment
298
            $now        = $this->dateHelper->getCurrentDateTime();
299
            $diff       = $start->diff($now);
300
            $prevMoment = clone $prevStart;
301
            $prevMoment->add($diff);
302
303
            $data = array_merge(
304
                $data,
305
                [
306
                    'current_moment' => $now,
307
                    'prev_start'     => $prevStart->format('Y-m-d'),
308
                    'prev_end'       => $prevEnd->format('Y-m-d'),
309
                    'prev_moment'    => $prevMoment
310
                ]
311
            );
312
        }
313
314
        return $data;
315
    }
316
}
317