Passed
Pull Request — master (#82)
by
unknown
04:31 queued 01:31
created

WcPagantisNotify::setProduct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 1
b 0
f 0
nc 1
nop 1
dl 0
loc 3
rs 10
1
<?php
2
3
use Pagantis\OrdersApiClient\Client;
4
use Pagantis\ModuleUtils\Exception\ConcurrencyException;
5
use Pagantis\ModuleUtils\Exception\AlreadyProcessedException;
6
use Pagantis\ModuleUtils\Exception\AmountMismatchException;
7
use Pagantis\ModuleUtils\Exception\MerchantOrderNotFoundException;
8
use Pagantis\ModuleUtils\Exception\NoIdentificationException;
9
use Pagantis\ModuleUtils\Exception\OrderNotFoundException;
10
use Pagantis\ModuleUtils\Exception\QuoteNotFoundException;
11
use Pagantis\ModuleUtils\Exception\UnknownException;
12
use Pagantis\ModuleUtils\Exception\WrongStatusException;
13
use Pagantis\ModuleUtils\Model\Response\JsonSuccessResponse;
14
use Pagantis\ModuleUtils\Model\Response\JsonExceptionResponse;
15
use Pagantis\ModuleUtils\Model\Log\LogEntry;
16
use Pagantis\OrdersApiClient\Model\Order;
17
18
if (!defined('ABSPATH')) {
19
    exit;
20
}
21
22
class WcPagantisNotify extends WcPagantisGateway
23
{
24
25
26
    /** Seconds to expire a locked request */
27
    const CONCURRENCY_TIMEOUT = 5;
28
29
    /** @var mixed $pagantisOrder */
30
    protected $pagantisOrder;
31
32
    /** @var $string $origin */
0 ignored issues
show
Documentation Bug introduced by
The doc comment $string at position 0 could not be parsed: Unknown type name '$string' at position 0 in $string.
Loading history...
33
    public $origin;
34
35
    /** @var $string */
0 ignored issues
show
Documentation Bug introduced by
The doc comment $string at position 0 could not be parsed: Unknown type name '$string' at position 0 in $string.
Loading history...
36
    public $order;
37
38
    /** @var mixed $woocommerceOrderId */
39
    protected $woocommerceOrderId = '';
40
41
    /** @var mixed $cfg */
42
    protected $cfg;
43
44
    /** @var Client $orderClient */
45
    protected $orderClient;
46
47
    /** @var  WC_Order $woocommerceOrder */
0 ignored issues
show
Bug introduced by
The type WC_Order 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...
48
    protected $woocommerceOrder;
49
50
    /** @var mixed $pagantisOrderId */
51
    protected $pagantisOrderId = '';
52
53
    /** @var $string */
0 ignored issues
show
Documentation Bug introduced by
The doc comment $string at position 0 could not be parsed: Unknown type name '$string' at position 0 in $string.
Loading history...
54
    protected $product;
55
56
    /** @var $string */
0 ignored issues
show
Documentation Bug introduced by
The doc comment $string at position 0 could not be parsed: Unknown type name '$string' at position 0 in $string.
Loading history...
57
    protected $verificationToken = null;
58
59
    /**
60
     * Validation vs PagantisClient
61
     *
62
     * @return JsonExceptionResponse|JsonSuccessResponse
63
     * @throws ConcurrencyException
64
     */
65
    public function processNotification()
66
    {
67
        try {
68
            require_once(__ROOT__ . '/vendor/autoload.php');
69
            try {
70
                if ($_SERVER['REQUEST_METHOD'] == 'GET' && $_GET['origin'] == 'notification') {
71
                    return $this->buildResponse();
72
                }
73
74
                $this->setWoocommerceOrderId();
75
                $this->setVerificationToken();
76
                $this->verifyOrderConformity();
77
                $this->checkConcurrency();
78
                $this->setPaymentProductType();
79
                $this->getMerchantOrder();
80
                $this->setPagantisOrderId();
81
                $this->getPagantisOrder();
82
                $checkAlreadyProcessed = $this->checkOrderStatus();
83
                if ($checkAlreadyProcessed) {
84
                    return $this->buildResponse();
85
                }
86
                $this->validateAmount();
87
                if ($this->checkMerchantOrderStatus()) {
88
                    $this->processMerchantOrder();
89
                }
90
            } catch (\Exception $exception) {
91
                $this->insertLog($exception);
92
93
                return $this->buildResponse($exception);
94
            }
95
96
            try {
97
                $this->confirmPagantisOrder();
98
99
                return $this->buildResponse();
100
            } catch (\Exception $exception) {
101
                $this->rollbackMerchantOrder();
102
                $this->insertLog($exception);
103
104
                return $this->buildResponse($exception);
105
            }
106
        } catch (\Exception $exception) {
107
            $this->insertLog($exception);
108
            return $this->buildResponse($exception);
109
        }
110
    }
111
112
    /**
113
     * COMMON FUNCTIONS
114
     */
115
116
    /**
117
     * @throws ConcurrencyException
118
     */
119
    private function checkConcurrency()
120
    {
121
        $this->unblockConcurrency();
122
        $this->blockConcurrency($this->woocommerceOrderId);
123
    }
124
125
    /**
126
     * getProductType
127
     */
128
    private function setPaymentProductType()
129
    {
130
        if ($_GET['product'] == '') {
131
            $this->setProduct(WcPagantisGateway::METHOD_ID);
132
        } else {
133
            $this->setProduct($_GET['product']);
134
        }
135
    }
136
137
    /**
138
     * @throws MerchantOrderNotFoundException
139
     */
140
    private function getMerchantOrder()
141
    {
142
        try {
143
            $this->woocommerceOrder = new WC_Order($this->woocommerceOrderId);
144
            $this->woocommerceOrder->set_payment_method_title($this->getProduct());
145
        } catch (\Exception $e) {
146
            throw new MerchantOrderNotFoundException();
147
        }
148
    }
149
150
    /**
151
     * @throws MerchantOrderNotFoundException
152
     */
153
    private function verifyOrderConformity()
154
    {
155
        global $wpdb;
156
        $this->checkDbTable();
157
        $tableName =$wpdb->prefix . PG_OLD_CART_PROCESS_TABLE;
158
        $tokenCount=$wpdb->get_var($wpdb->prepare(
159
            "SELECT COUNT(wc_order_id) 
160
                                                                    FROM $tableName 
161
                                                                    WHERE token = %s",
162
            $this->getVerificationToken()
163
        ));
164
        $orderIDCount = $wpdb->get_var(
165
            $wpdb->prepare(
166
                "SELECT COUNT(token) 
167
                                        FROM $tableName 
168
                                        WHERE wc_order_id = %s",
169
                $this->getWoocommerceOrderId()
170
            )
171
        );
172
        if (!($tokenCount == 1 && $orderIDCount == 1)) {
173
            throw new MerchantOrderNotFoundException();
174
        }
175
    }
176
177
    private function getPagantisOrderIdFromDB()
178
    {
179
        global $wpdb;
180
        $this->checkDbTable();
181
        $tableName = $wpdb->prefix.PG_OLD_CART_PROCESS_TABLE;
182
        $queryResult = $wpdb->get_row("SELECT order_id FROM $tableName WHERE token='{$this->getVerificationToken()}'");
183
184
        return $queryResult->order_id;
185
    }
186
187
    /**
188
     * @throws NoIdentificationException
189
     */
190
    private function setPagantisOrderId()
191
    {
192
        $this->pagantisOrderId = $this->getPagantisOrderIdFromDB();
193
194
        if (empty($this->pagantisOrderId)) {
195
            throw new NoIdentificationException();
196
        }
197
    }
198
199
    /**
200
     * @throws OrderNotFoundException
201
     */
202
    private function getPagantisOrder()
203
    {
204
        try {
205
            $this->cfg = get_option('woocommerce_pagantis_settings');
0 ignored issues
show
Bug introduced by
The function get_option 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

205
            $this->cfg = /** @scrutinizer ignore-call */ get_option('woocommerce_pagantis_settings');
Loading history...
206
            $this->cfg = get_option('woocommerce_pagantis_settings');
207
            if ($this->isProduct4x()) {
208
                $publicKey = $this->cfg['pagantis_public_key_4x'];
209
                $secretKey = $this->cfg['pagantis_private_key_4x'];
210
            } else {
211
                $publicKey = $this->cfg['pagantis_public_key'];
212
                $secretKey = $this->cfg['pagantis_private_key'];
213
            }
214
215
            $this->orderClient = new Client($publicKey, $secretKey);
216
            $this->pagantisOrder = $this->orderClient->getOrder($this->pagantisOrderId);
217
        } catch (\Exception $e) {
218
            throw new OrderNotFoundException();
219
        }
220
    }
221
222
    /**
223
     * @return bool
224
     * @throws WrongStatusException
225
     */
226
    private function checkOrderStatus()
227
    {
228
        try {
229
            $this->checkPagantisStatus(array('AUTHORIZED'));
230
        } catch (\Exception $e) {
231
            if ($this->pagantisOrder instanceof Order) {
232
                $status = $this->pagantisOrder->getStatus();
233
            } else {
234
                $status = '-';
235
            }
236
237
            if ($status === Order::STATUS_CONFIRMED) {
238
                return true;
239
            }
240
            throw new WrongStatusException($status);
241
        }
242
    }
243
244
    /**
245
     * @return bool
246
     */
247
    private function checkMerchantOrderStatus()
248
    {
249
        //Order status reference => https://docs.woocommerce.com/document/managing-orders/
250
        $validStatus=array('on-hold', 'pending', 'failed', 'processing', 'completed');
251
        $isValidStatus = apply_filters(
0 ignored issues
show
Bug introduced by
The function apply_filters 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

251
        $isValidStatus = /** @scrutinizer ignore-call */ apply_filters(
Loading history...
252
            'woocommerce_valid_order_statuses_for_payment_complete',
253
            $validStatus,
254
            $this
255
        );
256
257
        if (!$this->woocommerceOrder->has_status($isValidStatus)) { // TO CONFIRM
258
            $logMessage = "WARNING checkMerchantOrderStatus." .
259
                          " Merchant order id:".$this->woocommerceOrder->get_id().
260
                          " Merchant order status:".$this->woocommerceOrder->get_status().
261
                          " Pagantis order id:".$this->pagantisOrder->getStatus().
262
                          " Pagantis order status:".$this->pagantisOrder->getId().
263
                          " Pagantis urlToken: ".$this->getVerificationToken();
264
            
265
            $this->insertLog(null, $logMessage);
266
            $this->woocommerceOrder->add_order_note($logMessage);
267
            $this->woocommerceOrder->save();
268
            return false;
269
        }
270
271
        return true; //TO SAVE
272
    }
273
274
    /**
275
     * @throws AmountMismatchException
276
     */
277
    private function validateAmount()
278
    {
279
        $pagantisAmount = $this->pagantisOrder->getShoppingCart()->getTotalAmount();
280
        $wcAmount = intval(strval(100 * $this->woocommerceOrder->get_total()));
281
        if ($pagantisAmount != $wcAmount) {
282
            throw new AmountMismatchException($pagantisAmount, $wcAmount);
283
        }
284
    }
285
286
    /**
287
     * @throws Exception
288
     */
289
    private function processMerchantOrder()
290
    {
291
        $this->saveOrder();
292
        $this->updateBdInfo();
293
    }
294
295
    /**
296
     * @return false|string
297
     * @throws UnknownException
298
     */
299
    private function confirmPagantisOrder()
300
    {
301
        try {
302
            $this->pagantisOrder = $this->orderClient->confirmOrder($this->pagantisOrderId);
303
        } catch (\Exception $e) {
304
            $this->pagantisOrder = $this->orderClient->getOrder($this->pagantisOrderId);
305
            if ($this->pagantisOrder->getStatus() !== Order::STATUS_CONFIRMED) {
306
                throw new UnknownException($e->getMessage());
307
            } else {
308
                $logMessage = 'Concurrency issue: Order_id ' . $this->pagantisOrderId . ' was confirmed by other process';
309
                $this->insertLog(null, $logMessage);
310
            }
311
        }
312
313
        $jsonResponse = new JsonSuccessResponse();
314
315
        return $jsonResponse->toJson();
316
    }
317
318
    /**
319
     * UTILS FUNCTIONS
320
     */
321
    /** STEP 1 CC - Check concurrency */
322
323
    /**
324
     * Check if cart processing table exists
325
     */
326
    private function checkDbTable()
327
    {
328
        if (isPgTableCreated(PG_OLD_CART_PROCESS_TABLE)) {
329
            alterCartProcessingTable();
330
        } else {
331
            createOrderProcessingTable();
332
        }
333
    }
334
335
    /**
336
     * Check if logs table exists
337
     */
338
    private function checkDbLogTable()
339
    {
340
        global $wpdb;
341
        $tableName = $wpdb->prefix.PG_LOGS_TABLE_NAME;
342
343
        if ($wpdb->get_var("SHOW TABLES LIKE '$tableName'") != $tableName) {
344
            $charset_collate = $wpdb->get_charset_collate();
345
            $sql = "CREATE TABLE $tableName ( id int NOT NULL AUTO_INCREMENT, log text NOT NULL, 
346
                    createdAt timestamp DEFAULT CURRENT_TIMESTAMP, UNIQUE KEY id (id)) $charset_collate";
347
348
            require_once(ABSPATH.'wp-admin/includes/upgrade.php');
0 ignored issues
show
Bug introduced by
The constant ABSPATH was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
349
            dbDelta($sql);
0 ignored issues
show
Bug introduced by
The function dbDelta 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

349
            /** @scrutinizer ignore-call */ 
350
            dbDelta($sql);
Loading history...
350
        }
351
        return;
352
    }
353
354
    /** STEP 2 GMO - Get Merchant Order */
355
    /** STEP 3 GPOI - Get Pagantis OrderId */
356
    /** STEP 4 GPO - Get Pagantis Order */
357
    /** STEP 5 COS - Check Order Status */
358
359
    /**
360
     * @param $statusArray
361
     *
362
     * @throws \Exception
363
     */
364
    private function checkPagantisStatus($statusArray)
365
    {
366
        $pagantisStatus = array();
367
        foreach ($statusArray as $status) {
368
            $pagantisStatus[] = constant("\Pagantis\OrdersApiClient\Model\Order::STATUS_$status");
369
        }
370
371
        if ($this->pagantisOrder instanceof Order) {
372
            $isOrderStatusValid = in_array($this->pagantisOrder->getStatus(), $pagantisStatus);
373
            if (!$isOrderStatusValid) {
374
                if ($this->pagantisOrder instanceof Order) {
0 ignored issues
show
introduced by
$this->pagantisOrder is always a sub-type of Pagantis\OrdersApiClient\Model\Order.
Loading history...
375
                    $status = $this->pagantisOrder->getStatus();
376
                } else {
377
                    $status = '-';
378
                }
379
                throw new WrongStatusException($status);
380
            }
381
        } else {
382
            throw new OrderNotFoundException();
383
        }
384
    }
385
386
    /** STEP 6 CMOS - Check Merchant Order Status */
387
    /** STEP 7 VA - Validate Amount */
388
    /** STEP 8 PMO - Process Merchant Order */
389
    /**
390
     * @throws \Exception
391
     */
392
    private function saveOrder()
393
    {
394
        global $woocommerce;
395
        $paymentResult = $this->woocommerceOrder->payment_complete();
396
        if ($paymentResult) {
397
            $metadataOrder = $this->pagantisOrder->getMetadata();
398
            $metadataInfo  = null;
399
            foreach ($metadataOrder as $metadataKey => $metadataValue) {
400
                if ($metadataKey == 'promotedProduct') {
401
                    $metadataInfo .= "/Producto promocionado = $metadataValue";
402
                }
403
            }
404
405
            if ($metadataInfo != null) {
0 ignored issues
show
Bug introduced by
It seems like you are loosely comparing $metadataInfo of type null|string against null; this is ambiguous if the string can be empty. Consider using a strict comparison !== instead.
Loading history...
406
                $this->woocommerceOrder->add_order_note($metadataInfo);
407
            }
408
409
            $this->woocommerceOrder->add_order_note("Notification received via $this->origin");
410
            $this->woocommerceOrder->reduce_order_stock();
411
            $this->woocommerceOrder->save();
412
413
            $woocommerce->cart->empty_cart();
414
            sleep(3);
415
        } else {
416
            throw new UnknownException('Order can not be saved');
417
        }
418
    }
419
420
    /**
421
     * Save the merchant order_id with the related identification
422
     */
423
    private function updateBdInfo()
424
    {
425
        global $wpdb;
426
427
        $this->checkDbTable();
428
        $tableName = $wpdb->prefix . PG_OLD_CART_PROCESS_TABLE;
429
430
        $wpdb->update(
431
            $tableName,
432
            array('wc_order_id' => $this->woocommerceOrderId),
433
            array('token' => $this->getVerificationToken()),
434
            array('%s'),
435
            array('%s')
436
        );
437
    }
438
439
    /** STEP 9 CPO - Confirmation Pagantis Order */
440
    private function rollbackMerchantOrder()
441
    {
442
        $this->woocommerceOrder->update_status('pending', __('Pending payment', 'woocommerce'));
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

442
        $this->woocommerceOrder->update_status('pending', /** @scrutinizer ignore-call */ __('Pending payment', 'woocommerce'));
Loading history...
443
    }
444
445
    /**
446
     * @param null $exception
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $exception is correct as it would always require null to be passed?
Loading history...
447
     * @param null $message
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $message is correct as it would always require null to be passed?
Loading history...
448
     */
449
    private function insertLog($exception = null, $message = null)
450
    {
451
        global $wpdb;
452
453
        $this->checkDbLogTable();
454
        $logEntry = new LogEntry();
455
        if ($exception instanceof \Exception) {
456
            $logEntry = $logEntry->error($exception);
457
        } else {
458
            $logEntry = $logEntry->info($message);
459
        }
460
461
        $tableName = $wpdb->prefix . PG_LOGS_TABLE_NAME;
462
        $wpdb->insert($tableName, array('log' => $logEntry->toJson()));
463
    }
464
465
    /**
466
     * @param null $orderId
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $orderId is correct as it would always require null to be passed?
Loading history...
467
     *
468
     * @throws ConcurrencyException
469
     */
470
    private function unblockConcurrency($orderId = null)
471
    {
472
        global $wpdb;
473
        $tableName = $wpdb->prefix . PG_CONCURRENCY_TABLE_NAME;
474
        if ($orderId == null) {
0 ignored issues
show
introduced by
The condition $orderId == null is always true.
Loading history...
475
            $query = "DELETE FROM $tableName WHERE createdAt<(NOW()- INTERVAL " . self::CONCURRENCY_TIMEOUT . " SECOND)";
476
        } else {
477
            $query = "DELETE FROM $tableName WHERE order_id = $orderId";
478
        }
479
        $resultDelete = $wpdb->query($query);
480
        if ($resultDelete === false) {
481
            throw new ConcurrencyException();
482
        }
483
    }
484
485
    /**
486
     * @param $orderId
487
     *
488
     * @throws ConcurrencyException
489
     */
490
    private function blockConcurrency($orderId)
491
    {
492
        global $wpdb;
493
        $tableName = $wpdb->prefix.PG_CONCURRENCY_TABLE_NAME;
494
        $insertResult = $wpdb->insert($tableName, array('order_id' => $orderId));
495
        if ($insertResult === false) {
496
            if ($this->getOrigin() == 'Notify') {
497
                throw new ConcurrencyException();
498
            } else {
499
                $query           =
500
                    sprintf(
501
                        "SELECT TIMESTAMPDIFF(SECOND,NOW()-INTERVAL %s SECOND, createdAt) as rest FROM %s WHERE %s",
502
                        self::CONCURRENCY_TIMEOUT,
503
                        $tableName,
504
                        "order_id=$orderId"
505
                    );
506
                $resultSeconds=$wpdb->get_row($query);
507
                $restSeconds  =isset($resultSeconds) ? ($resultSeconds->rest) : 0;
508
                $secondsToExpire = ($restSeconds > self::CONCURRENCY_TIMEOUT) ? self::CONCURRENCY_TIMEOUT : $restSeconds;
509
                sleep($secondsToExpire + 1);
510
511
                $logMessage =
512
                    sprintf(
513
                        "User waiting %s seconds, default seconds %s, bd time to expire %s seconds",
514
                        $secondsToExpire,
515
                        self::CONCURRENCY_TIMEOUT,
516
                        $restSeconds
517
                    );
518
                $this->insertLog(null, $logMessage);
519
            }
520
        }
521
    }
522
523
    /**
524
     * @param null $exception
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $exception is correct as it would always require null to be passed?
Loading history...
525
     *
526
     *
527
     * @return JsonExceptionResponse|JsonSuccessResponse
528
     * @throws ConcurrencyException
529
     */
530
    private function buildResponse($exception = null)
531
    {
532
        $this->unblockConcurrency($this->woocommerceOrderId);
533
534
        if ($exception == null) {
0 ignored issues
show
introduced by
The condition $exception == null is always true.
Loading history...
535
            $jsonResponse = new JsonSuccessResponse();
536
        } else {
537
            $jsonResponse = new JsonExceptionResponse();
538
            $jsonResponse->setException($exception);
539
        }
540
        $jsonResponse->setMerchantOrderId($this->woocommerceOrderId);
541
        $jsonResponse->setPagantisOrderId($this->pagantisOrderId);
542
543
        if ($_SERVER['REQUEST_METHOD'] == 'POST') {
544
            $jsonResponse->printResponse();
545
        } else {
546
            return $jsonResponse;
547
        }
548
    }
549
550
    /**
551
     * GETTERS & SETTERS
552
     */
553
554
    /**
555
     * @return mixed
556
     */
557
    public function getOrigin()
558
    {
559
        return $this->origin;
560
    }
561
562
    /**
563
     * @param mixed $origin
564
     */
565
    public function setOrigin($origin)
566
    {
567
        $this->origin = $origin;
568
    }
569
570
    /**
571
     * @return bool
572
     */
573
    private function isProduct4x()
574
    {
575
        return ($this->product === Ucfirst(WcPagantis4xGateway::METHOD_ID));
576
    }
577
578
    /**
579
     * @return mixed
580
     */
581
    public function getProduct()
582
    {
583
        return $this->product;
584
    }
585
586
    /**
587
     * @param mixed $product
588
     */
589
    public function setProduct($product)
590
    {
591
        $this->product = Ucfirst($product);
592
    }
593
594
    /**
595
     * @return mixed
596
     */
597
    public function getWoocommerceOrderId()
598
    {
599
        return $this->woocommerceOrderId;
600
    }
601
602
    /**
603
     * @throws QuoteNotFoundException
604
     */
605
    public function setWoocommerceOrderId()
606
    {
607
        $this->woocommerceOrderId = $_GET['order-received'];
608
        if ($this->woocommerceOrderId == '') {
609
            throw new QuoteNotFoundException();
610
        }
611
    }
612
613
    /**
614
     * @return mixed
615
     */
616
    private function getVerificationToken()
617
    {
618
        return $this->verificationToken;
619
    }
620
621
    /**
622
     * @throws MerchantOrderNotFoundException
623
     */
624
    private function setVerificationToken()
625
    {
626
        $this->verificationToken = $_GET['token'];
627
628
        if (is_null($this->verificationToken)) {
629
            throw new MerchantOrderNotFoundException();
630
        }
631
    }
632
}
633