Completed
Push — master ( 0dbe68...17d58d )
by Florian
04:25
created

Addresscheck::handleAddresscheck()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 11
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

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

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
255
        }
256
257
        return __($sCustomermessage);
258
    }
259
260
    /**
261
     * Return error message
262
     *
263
     * @return string
264
     */
265
    public function getErrorMessage()
266
    {
267
        $sErrorMessage = $this->getConfigParam('stop_checkout_message');
268
        if (empty($sErrorMessage)) { // add default errormessage if none is configured
269
            $sErrorMessage = 'An error occured during the addresscheck.';
270
        }
271
        return $sErrorMessage;
272
    }
273
274
    /**
275
     * Get error message by the given response
276
     *
277
     * @param  array $aResponse
278
     * @return string
279
     */
280
    public function getErrorMessageByResponse($aResponse)
281
    {
282
        $sErrorMessage = false;
283
        if (!isset($aResponse['status'])) { // the response doesnt have the expected format
284
            $sErrorMessage = 'An error occured during the addresscheck.';
285
        } elseif ($aResponse['status'] == 'INVALID') {
286
            $sErrorMessage = $this->getInvalidMessage($aResponse['customermessage']);
287
        } elseif ($aResponse['status'] == 'ERROR') {
288
            if ($this->getConfigParam('handle_response_error') == 'stop_checkout') {
289
                $sErrorMessage = $this->getErrorMessage();
290
            }
291
        }
292
        return $sErrorMessage;
293
    }
294
295
    /**
296
     * Execute addresscheck and return the response
297
     *
298
     * @param  AddressInterface $oAddress
299
     * @return array
300
     */
301
302
    /**
303
     *
304
     * @param AddressInterface $oAddress
305
     * @return type
306
     * @throws LocalizedException
307
     */
308
    protected function handleAddresscheck(AddressInterface $oAddress)
309
    {
310
        $aResponse = $this->getResponse($oAddress);
311
        if (is_array($aResponse)) {
312
            $sErrorMessage = $this->getErrorMessageByResponse($aResponse);
313
            if (!empty($sErrorMessage)) {
314
                throw new LocalizedException(__($sErrorMessage));
315
            }
316
        }
317
        return $aResponse;
318
    }
319
320
    /**
321
     * Get score from session or from a new addresscheck and add it to the address
322
     *
323
     * @param  AddressInterface $oAddress
324
     * @param  Quote            $oQuote
325
     * @param  bool             $blIsBillingAddress
326
     * @return AddressInterface
327
     */
328
    public function handleAddressManagement(AddressInterface $oAddress, Quote $oQuote, $blIsBillingAddress = true)
329
    {
330
        $sScore = $this->checkoutSession->getPayoneBillingAddresscheckScore();
331
        if ($blIsBillingAddress === false) {
332
            $sScore = $this->checkoutSession->getPayoneShippingAddresscheckScore();
333
        }
334
        $this->checkoutSession->unsPayoneBillingAddresscheckScore();
335
        $this->checkoutSession->unsPayoneShippingAddresscheckScore();
336
337
        if (!$sScore && empty($oAddress->getPayoneAddresscheckScore())) {
338
            if ($this->isCheckNeededForQuote(false, $oQuote->isVirtual(), $oQuote->getSubtotal())) {
339
                $aResponse = $this->handleAddresscheck($oAddress);
340
                if (isset($aResponse['status']) && $aResponse['status'] == 'VALID') {
341
                    $oAddress = $this->correctAddress($oAddress);
342
                }
343
                $sScore = $this->getScore($oAddress);
344
            }
345
        }
346
        if ($sScore) {
347
            $oAddress->setPayoneAddresscheckScore($sScore);
348
        }
349
        return $oAddress;
350
    }
351
352
    /**
353
     * Get score from response or an old saved score from the database
354
     *
355
     * @param  AddressInterface $oAddress
356
     * @return string
357
     */
358
    public function getScore(AddressInterface $oAddress)
359
    {
360
        $aResponse = $this->getResponse($oAddress);
361
362
        $sScore = 'G';
363
        if (isset($aResponse['status']) && $aResponse['status'] == 'INVALID') {
364
            $sScore = 'R';
365
        } elseif (isset($aResponse['personstatus'])) {
366
            $sPersonStatus = $aResponse['personstatus'];
367
            if ($sPersonStatus != 'NONE') {
368
                $aMapping = $this->getPersonstatusMapping();
369
                if (array_key_exists($sPersonStatus, $aMapping)) {
370
                    $sScore = $aMapping[$sPersonStatus];
371
                }
372
            }
373
        } elseif ($this->isLifetimeStillValid()) {
374
            $sScore = $this->databaseHelper->getOldAddressStatus($oAddress, false);
375
        }
376
        return $sScore;
377
    }
378
379
    /**
380
     * Perform the PAYONE addresscheck request and return the response
381
     *
382
     * @param  AddressInterface $oAddress
383
     * @param  bool             $blIsBillingAddress
384
     * @return array|bool
385
     */
386
    public function getResponse(AddressInterface $oAddress, $blIsBillingAddress = false)
387
    {
388
        if ($this->aResponse === null) {
389
            $this->aResponse = $this->addresscheck->sendRequest($oAddress, $blIsBillingAddress);
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->addresscheck->sen...s, $blIsBillingAddress) can also be of type boolean. However, the property $aResponse is declared as type array. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
390
            if ($this->aResponse === true) {
391
                $this->blIsLifetimeValid = true;
392
            }
393
        }
394
        return $this->aResponse;
395
    }
396
}
397