Addresscheck   C
last analyzed

Complexity

Total Complexity 56

Size/Duplication

Total Lines 377
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 115
dl 0
loc 377
rs 5.5199
c 1
b 0
f 0
wmc 56

15 Methods

Rating   Name   Duplication   Size   Complexity  
A getErrorMessage() 0 7 2
A handleAddresscheck() 0 10 3
B isCheckNeededForQuote() 0 18 10
A correctAddress() 0 26 5
B getScore() 0 19 7
A getResponse() 0 9 3
A getPersonstatusMapping() 0 15 3
A isLifetimeStillValid() 0 3 1
B handleAddressManagement() 0 24 8
A getErrorMessageByResponse() 0 17 6
A getInvalidMessage() 0 11 2
A __construct() 0 12 1
A isAddressCorrected() 0 3 1
A getConfigParam() 0 3 1
A correctSingleField() 0 8 3

How to fix   Complexity   

Complex Class

Complex classes like Addresscheck often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Addresscheck, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/**
4
 * PAYONE Magento 2 Connector is free software: you can redistribute it and/or modify
5
 * it under the terms of the GNU Lesser General Public License as published by
6
 * the Free Software Foundation, either version 3 of the License, or
7
 * (at your option) any later version.
8
 *
9
 * PAYONE Magento 2 Connector is distributed in the hope that it will be useful,
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 * GNU Lesser General Public License for more details.
13
 *
14
 * You should have received a copy of the GNU Lesser General Public License
15
 * along with PAYONE Magento 2 Connector. If not, see <http://www.gnu.org/licenses/>.
16
 *
17
 * PHP version 5
18
 *
19
 * @category  Payone
20
 * @package   Payone_Magento2_Plugin
21
 * @author    FATCHIP GmbH <[email protected]>
22
 * @copyright 2003 - 2016 Payone GmbH
23
 * @license   <http://www.gnu.org/licenses/> GNU Lesser General Public License
24
 * @link      http://www.payone.de
25
 */
26
27
namespace Payone\Core\Model\Risk;
28
29
use Magento\Quote\Api\Data\AddressInterface;
0 ignored issues
show
Bug introduced by
The type Magento\Quote\Api\Data\AddressInterface was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
30
use Magento\Quote\Model\Quote;
0 ignored issues
show
Bug introduced by
The type Magento\Quote\Model\Quote was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
31
use Magento\Framework\Exception\LocalizedException;
0 ignored issues
show
Bug introduced by
The type Magento\Framework\Exception\LocalizedException was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
32
33
/**
34
 * Model for calling the addresscheck request
35
 */
36
class Addresscheck
37
{
38
    /**
39
     * Response from the PAYONE addresscheck request
40
     *
41
     * @var array
42
     */
43
    protected $aResponse = null;
44
45
    /**
46
     * Determines if the request was NOT executed because the lifetime of the last was still valid
47
     *
48
     * @var bool
49
     */
50
    protected $blIsLifetimeValid;
51
52
    /**
53
     * Saves if the address was corrected
54
     *
55
     * @var bool
56
     */
57
    protected $addressCorrected;
58
59
    /**
60
     * PAYONE addresscheck request model
61
     *
62
     * @var \Payone\Core\Model\Api\Request\Addresscheck
63
     */
64
    protected $addresscheck;
65
66
    /**
67
     * PAYONE database helper
68
     *
69
     * @var \Payone\Core\Helper\Database
70
     */
71
    protected $databaseHelper;
72
73
    /**
74
     * PAYONE toolkit helper
75
     *
76
     * @var \Payone\Core\Helper\Toolkit
77
     */
78
    protected $toolkitHelper;
79
80
    /**
81
     * Checkout session
82
     *
83
     * @var \Magento\Checkout\Model\Session
0 ignored issues
show
Bug introduced by
The type Magento\Checkout\Model\Session was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
84
     */
85
    protected $checkoutSession;
86
87
    /**
88
     * Quote repository.
89
     *
90
     * @var \Magento\Quote\Api\CartRepositoryInterface
0 ignored issues
show
Bug introduced by
The type Magento\Quote\Api\CartRepositoryInterface was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
91
     */
92
    protected $quoteRepository;
93
94
    /**
95
     * Constructor
96
     *
97
     * @param \Payone\Core\Model\Api\Request\Addresscheck $addresscheck
98
     * @param \Payone\Core\Helper\Database                $databaseHelper
99
     * @param \Payone\Core\Helper\Toolkit                 $toolkitHelper
100
     * @param \Magento\Checkout\Model\Session             $checkoutSession
101
     * @param \Magento\Quote\Api\CartRepositoryInterface  $quoteRepository
102
     */
103
    public function __construct(
104
        \Payone\Core\Model\Api\Request\Addresscheck $addresscheck,
105
        \Payone\Core\Helper\Database $databaseHelper,
106
        \Payone\Core\Helper\Toolkit $toolkitHelper,
107
        \Magento\Checkout\Model\Session $checkoutSession,
108
        \Magento\Quote\Api\CartRepositoryInterface $quoteRepository
109
    ) {
110
        $this->addresscheck = $addresscheck;
111
        $this->databaseHelper = $databaseHelper;
112
        $this->toolkitHelper = $toolkitHelper;
113
        $this->checkoutSession = $checkoutSession;
114
        $this->quoteRepository = $quoteRepository;
115
    }
116
117
    /**
118
     * Return if check was not executed because the lifetime of the last check was still valid
119
     *
120
     * @return bool
121
     */
122
    public function isLifetimeStillValid()
123
    {
124
        return $this->blIsLifetimeValid;
125
    }
126
127
    /**
128
     * Return addressCorrected property
129
     *
130
     * @return bool
131
     */
132
    public function isAddressCorrected()
133
    {
134
        return $this->addressCorrected;
135
    }
136
137
    /**
138
     * Get addresscheck config parameter
139
     *
140
     * @param  string $sParam
141
     * @param  string $sGroup
142
     * @return string
143
     */
144
    public function getConfigParam($sParam, $sGroup = 'address_check')
145
    {
146
        return $this->databaseHelper->getConfigParam($sParam, $sGroup, 'payone_protect');
147
    }
148
149
    /**
150
     * Correct a single address field if needed
151
     *
152
     * @param  AddressInterface $oAddress
153
     * @param  array            $aResponse
154
     * @param  string           $sArrayKey
155
     * @param  string           $sPropertyName
156
     * @return AddressInterface
157
     */
158
    protected function correctSingleField(AddressInterface $oAddress, $aResponse, $sArrayKey, $sPropertyName)
159
    {
160
        if (isset($aResponse[$sArrayKey]) && $aResponse[$sArrayKey] != $oAddress->getData($sPropertyName)) {
161
            $oAddress->setData($sPropertyName, $aResponse[$sArrayKey]);
162
            $this->addressCorrected = true;
163
        }
164
165
        return $oAddress;
166
    }
167
168
    /**
169
     * Change the address according to the response
170
     *
171
     * @param  AddressInterface $oAddress
172
     * @return AddressInterface
173
     */
174
    public function correctAddress(AddressInterface $oAddress)
175
    {
176
        $aResponse = $this->getResponse($oAddress);
177
        if (!is_array($aResponse)) {
0 ignored issues
show
introduced by
The condition is_array($aResponse) is always true.
Loading history...
178
            return $oAddress;
179
        }
180
181
        $this->addressCorrected = false;
182
        $oAddress = $this->correctSingleField($oAddress, $aResponse, 'firstname', 'firstname');
183
        $oAddress = $this->correctSingleField($oAddress, $aResponse, 'lastname', 'lastname');
184
        $oAddress = $this->correctSingleField($oAddress, $aResponse, 'zip', 'postcode');
185
        $oAddress = $this->correctSingleField($oAddress, $aResponse, 'city', 'city');
186
187
        if (isset($aResponse['street'])) {
188
            $sStreet = $oAddress->getStreet();
189
            if (is_array($sStreet)) {
190
                $sStreet = implode(' ', $sStreet);
191
            }
192
193
            if ($aResponse['street'] != $sStreet) {
194
                $oAddress->setStreet($aResponse['street']);
195
                $this->addressCorrected = true;
196
            }
197
        }
198
199
        return $oAddress;
200
    }
201
202
    /**
203
     * Check if the addresscheck needs to be executed for this quote
204
     *
205
     * @param  bool   $isBillingAddress
206
     * @param  bool   $isVirtual
207
     * @param  double $dTotal
208
     * @return bool
209
     */
210
    public function isCheckNeededForQuote($isBillingAddress, $isVirtual, $dTotal)
211
    {
212
        $dMinBasketValue = $this->getConfigParam('min_order_total');
213
        if (!empty($dMinBasketValue) && is_numeric($dMinBasketValue) && $dTotal < $dMinBasketValue) {
214
            return false;
215
        }
216
217
        $dMaxBasketValue = $this->getConfigParam('max_order_total');
218
        if (!empty($dMaxBasketValue) && is_numeric($dMaxBasketValue) && $dTotal > $dMaxBasketValue) {
219
            return false;
220
        }
221
222
        $blCheckVirtual = (bool)$this->getConfigParam('check_billing_for_virtual_order');
223
        if ($isBillingAddress === true && $isVirtual === true && $blCheckVirtual === false) {
224
            return false;
225
        }
226
227
        return true;
228
    }
229
230
    /**
231
     * Returns the personstatus mapping from addresscheck admin config
232
     *
233
     * @return array
234
     */
235
    public function getPersonstatusMapping()
236
    {
237
        $aReturnMappings = [];
238
239
        $sMappings = $this->getConfigParam('mapping', 'personstatus');
240
        $aMappings = $this->toolkitHelper->unserialize($sMappings);
241
        if (!is_array($aMappings)) {
242
            $aMappings = [];
243
        }
244
245
        foreach ($aMappings as $aMapping) {
246
            $aReturnMappings[$aMapping['personstatus']] = $aMapping['score'];
247
        }
248
249
        return $aReturnMappings;
250
    }
251
252
    /**
253
     * Get formatted invalid message
254
     *
255
     * @param  string $sCustomermessage
256
     * @return string
257
     */
258
    public function getInvalidMessage($sCustomermessage)
259
    {
260
        $sInvalidMessage = $this->getConfigParam('message_response_invalid');
261
        if (!empty($sInvalidMessage)) {
262
            $aSubstitutionArray = [
263
                '{{payone_customermessage}}' => __($sCustomermessage),
0 ignored issues
show
Bug introduced by
The function __ was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

263
                '{{payone_customermessage}}' => /** @scrutinizer ignore-call */ __($sCustomermessage),
Loading history...
264
            ];
265
            return $this->toolkitHelper->handleSubstituteReplacement($sInvalidMessage, $aSubstitutionArray, 255);
0 ignored issues
show
Bug introduced by
$aSubstitutionArray of type array is incompatible with the type string expected by parameter $aSubstitutionArray of Payone\Core\Helper\Toolk...SubstituteReplacement(). ( Ignorable by Annotation )

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

265
            return $this->toolkitHelper->handleSubstituteReplacement($sInvalidMessage, /** @scrutinizer ignore-type */ $aSubstitutionArray, 255);
Loading history...
266
        }
267
268
        return __($sCustomermessage);
269
    }
270
271
    /**
272
     * Return error message
273
     *
274
     * @return string
275
     */
276
    public function getErrorMessage()
277
    {
278
        $sErrorMessage = $this->getConfigParam('stop_checkout_message');
279
        if (empty($sErrorMessage)) { // add default errormessage if none is configured
280
            $sErrorMessage = 'An error occured during the addresscheck.';
281
        }
282
        return $sErrorMessage;
283
    }
284
285
    /**
286
     * Get error message by the given response
287
     *
288
     * @param  array $aResponse
289
     * @return string
290
     */
291
    public function getErrorMessageByResponse($aResponse)
292
    {
293
        $sErrorMessage = false;
294
        if (isset($aResponse['wrongCountry'])) {
295
            return $sErrorMessage;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $sErrorMessage returns the type false which is incompatible with the documented return type string.
Loading history...
296
        }
297
298
        if (!isset($aResponse['status'])) { // the response doesnt have the expected format
299
            $sErrorMessage = 'An error occured during the addresscheck.';
300
        } elseif ($aResponse['status'] == 'INVALID') {
301
            $sErrorMessage = $this->getInvalidMessage($aResponse['customermessage']);
302
        } elseif ($aResponse['status'] == 'ERROR') {
303
            if ($this->getConfigParam('handle_response_error') == 'stop_checkout') {
304
                $sErrorMessage = $this->getErrorMessage();
305
            }
306
        }
307
        return $sErrorMessage;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $sErrorMessage could also return false which is incompatible with the documented return type string. Did you maybe forget to handle an error condition?

If the returned type also contains false, it is an indicator that maybe an error condition leading to the specific return statement remains unhandled.

Loading history...
308
    }
309
310
    /**
311
     * Execute addresscheck and return the response
312
     *
313
     * @param  AddressInterface $oAddress
314
     * @return array
315
     */
316
317
    /**
318
     *
319
     * @param AddressInterface $oAddress
320
     * @param bool             $blIsBillingAddress
321
     * @return array
322
     * @throws LocalizedException
323
     */
324
    protected function handleAddresscheck(AddressInterface $oAddress, $blIsBillingAddress = false)
325
    {
326
        $aResponse = $this->getResponse($oAddress, $blIsBillingAddress);
327
        if (is_array($aResponse)) {
0 ignored issues
show
introduced by
The condition is_array($aResponse) is always true.
Loading history...
328
            $sErrorMessage = $this->getErrorMessageByResponse($aResponse);
329
            if (!empty($sErrorMessage)) {
330
                throw new LocalizedException(__($sErrorMessage));
0 ignored issues
show
Bug introduced by
The function __ was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

330
                throw new LocalizedException(/** @scrutinizer ignore-call */ __($sErrorMessage));
Loading history...
331
            }
332
        }
333
        return $aResponse;
334
    }
335
336
    /**
337
     * Get score from session or from a new addresscheck and add it to the address
338
     *
339
     * @param  AddressInterface $oAddress
340
     * @param  int              $iCartId
341
     * @param  bool             $blIsBillingAddress
342
     * @return AddressInterface
343
     */
344
    public function handleAddressManagement(AddressInterface $oAddress, $iCartId, $blIsBillingAddress = true)
345
    {
346
        $oQuote = $this->quoteRepository->getActive($iCartId);
347
348
        $sScore = $this->checkoutSession->getPayoneBillingAddresscheckScore();
349
        if ($blIsBillingAddress === false) {
350
            $sScore = $this->checkoutSession->getPayoneShippingAddresscheckScore();
351
        }
352
        $this->checkoutSession->unsPayoneBillingAddresscheckScore();
353
        $this->checkoutSession->unsPayoneShippingAddresscheckScore();
354
355
        if (!$sScore && empty($oAddress->getPayoneAddresscheckScore())) {
356
            if ($this->isCheckNeededForQuote($blIsBillingAddress, $oQuote->isVirtual(), $oQuote->getSubtotal())) {
357
                $aResponse = $this->handleAddresscheck($oAddress, $blIsBillingAddress);
358
                if (isset($aResponse['status']) && $aResponse['status'] == 'VALID') {
359
                    $oAddress = $this->correctAddress($oAddress);
360
                }
361
                $sScore = $this->getScore($oAddress);
362
            }
363
        }
364
        if ($sScore) {
365
            $oAddress->setPayoneAddresscheckScore($sScore);
366
        }
367
        return $oAddress;
368
    }
369
370
    /**
371
     * Get score from response or an old saved score from the database
372
     *
373
     * @param  AddressInterface $oAddress
374
     * @return string
375
     */
376
    public function getScore(AddressInterface $oAddress)
377
    {
378
        $aResponse = $this->getResponse($oAddress);
379
380
        $sScore = 'G';
381
        if (isset($aResponse['status']) && $aResponse['status'] == 'INVALID') {
382
            $sScore = 'R';
383
        } elseif (isset($aResponse['personstatus'])) {
384
            $sPersonStatus = $aResponse['personstatus'];
385
            if ($sPersonStatus != 'NONE') {
386
                $aMapping = $this->getPersonstatusMapping();
387
                if (array_key_exists($sPersonStatus, $aMapping)) {
388
                    $sScore = $aMapping[$sPersonStatus];
389
                }
390
            }
391
        } elseif ($this->isLifetimeStillValid()) {
392
            $sScore = $this->databaseHelper->getOldAddressStatus($oAddress, false);
393
        }
394
        return $sScore;
395
    }
396
397
    /**
398
     * Perform the PAYONE addresscheck request and return the response
399
     *
400
     * @param  AddressInterface $oAddress
401
     * @param  bool             $blIsBillingAddress
402
     * @return array|bool
403
     */
404
    public function getResponse(AddressInterface $oAddress, $blIsBillingAddress = false)
405
    {
406
        if ($this->aResponse === null) {
407
            $this->aResponse = $this->addresscheck->sendRequest($oAddress, $blIsBillingAddress);
408
            if ($this->aResponse === true) {
0 ignored issues
show
introduced by
The condition $this->aResponse === true is always false.
Loading history...
409
                $this->blIsLifetimeValid = true;
410
            }
411
        }
412
        return $this->aResponse;
413
    }
414
}
415