Completed
Push — 1.9 ( d8eb28...5c3e2e )
by
unknown
61:52 queued 29s
created

ForecastOfOpportunities::prepareDefaultOptions()   B

Complexity

Conditions 6
Paths 3

Size

Total Lines 22
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 22
rs 8.6738
cc 6
eloc 14
nc 3
nop 1

1 Method

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