Passed
Pull Request — master (#13)
by
unknown
02:29
created

WcPagantisNotify::processInformation()   B

Complexity

Conditions 5
Paths 108

Size

Total Lines 41
Code Lines 35

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 35
c 0
b 0
f 0
nc 108
nop 0
dl 0
loc 41
rs 8.9955
1
<?php
2
3
use Pagantis\OrdersApiClient\Client;
4
use Pagantis\ModuleUtils\Exception\AlreadyProcessedException;
5
use Pagantis\ModuleUtils\Exception\AmountMismatchException;
6
use Pagantis\ModuleUtils\Exception\MerchantOrderNotFoundException;
7
use Pagantis\ModuleUtils\Exception\NoIdentificationException;
8
use Pagantis\ModuleUtils\Exception\OrderNotFoundException;
9
use Pagantis\ModuleUtils\Exception\QuoteNotFoundException;
10
use Pagantis\ModuleUtils\Exception\UnknownException;
11
use Pagantis\ModuleUtils\Exception\WrongStatusException;
12
use Pagantis\ModuleUtils\Model\Response\JsonSuccessResponse;
13
use Pagantis\ModuleUtils\Model\Response\JsonExceptionResponse;
14
use Pagantis\ModuleUtils\Model\Log\LogEntry;
15
16
if (!defined('ABSPATH')) {
17
    exit;
18
}
19
20
class WcPagantisNotify extends WcPagantisGateway
21
{
22
    /** @var mixed $pagantisOrder */
23
    protected $pagantisOrder;
24
25
    /** @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...
26
    public $origin;
27
28
    /** @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...
29
    public $order;
30
31
    /** @var mixed $woocommerceOrderId */
32
    protected $woocommerceOrderId = '';
33
34
    /** @var mixed $cfg */
35
    protected $cfg;
36
37
    /** @var Client $orderClient */
38
    protected $orderClient;
39
40
    /** @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...
41
    protected $woocommerceOrder;
42
43
    /** @var mixed $pagantisOrderId */
44
    protected $pagantisOrderId = '';
45
46
    /**
47
     * Validation vs PagantisClient
48
     *
49
     * @return array|Array_
0 ignored issues
show
Bug introduced by
The type Array_ 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...
50
     * @throws Exception
51
     */
52
    public function processInformation()
53
    {
54
        require_once(__ROOT__.'/vendor/autoload.php');
55
        try {
56
            $this->checkConcurrency();
57
            $this->getMerchantOrder();
58
            $this->getPagantisOrderId();
59
            $this->getPagantisOrder();
60
            $this->checkOrderStatus();
61
            $this->checkMerchantOrderStatus();
62
            $this->validateAmount();
63
            $this->processMerchantOrder();
64
        } catch (\Exception $exception) {
65
            $jsonResponse = new JsonExceptionResponse();
66
            $jsonResponse->setMerchantOrderId($this->woocommerceOrderId);
67
            $jsonResponse->setPagantisOrderId($this->pagantisOrderId);
68
            $jsonResponse->setException($exception);
69
            $response = $jsonResponse->toJson();
70
            $this->insertLog($exception);
71
        }
72
        try {
73
            if (!isset($response)) {
74
                $this->confirmPagantisOrder();
75
                $jsonResponse = new JsonSuccessResponse();
76
                $jsonResponse->setMerchantOrderId($this->woocommerceOrderId);
77
                $jsonResponse->setPagantisOrderId($this->pagantisOrderId);
78
            }
79
        } catch (\Exception $exception) {
80
            $this->rollbackMerchantOrder();
81
            $jsonResponse = new JsonExceptionResponse();
82
            $jsonResponse->setMerchantOrderId($this->woocommerceOrderId);
83
            $jsonResponse->setPagantisOrderId($this->pagantisOrderId);
84
            $jsonResponse->setException($exception);
85
            $jsonResponse->toJson();
86
            $this->insertLog($exception);
87
        }
88
89
        if ($_SERVER['REQUEST_METHOD'] == 'POST') {
90
            $jsonResponse->printResponse();
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $jsonResponse does not seem to be defined for all execution paths leading up to this point.
Loading history...
91
        } else {
92
            return $jsonResponse;
93
        }
94
    }
95
96
    /**
97
     * COMMON FUNCTIONS
98
     */
99
100
    /**
101
     * @throws QuoteNotFoundException
102
     */
103
    private function checkConcurrency()
104
    {
105
        $this->woocommerceOrderId = $_GET['order-received'];
106
        if ($this->woocommerceOrderId == '') {
107
            throw new QuoteNotFoundException();
108
        }
109
    }
110
111
    /**
112
     * @throws MerchantOrderNotFoundException
113
     */
114
    private function getMerchantOrder()
115
    {
116
        try {
117
            $this->woocommerceOrder = new WC_Order($this->woocommerceOrderId);
118
        } catch (\Exception $e) {
119
            throw new MerchantOrderNotFoundException();
120
        }
121
    }
122
123
    /**
124
     * @throws NoIdentificationException
125
     */
126
    private function getPagantisOrderId()
127
    {
128
        global $wpdb;
129
        $this->checkDbTable();
130
        $tableName = $wpdb->prefix.self::ORDERS_TABLE;
131
        $queryResult = $wpdb->get_row("select order_id from $tableName where id='".$this->woocommerceOrderId."'");
132
        $this->pagantisOrderId = $queryResult->order_id;
133
134
        if ($this->pagantisOrderId == '') {
135
            throw new NoIdentificationException();
136
        }
137
    }
138
139
    /**
140
     * @throws OrderNotFoundException
141
     */
142
    private function getPagantisOrder()
143
    {
144
        try {
145
            $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

145
            $this->cfg = /** @scrutinizer ignore-call */ get_option('woocommerce_pagantis_settings');
Loading history...
146
            $this->orderClient = new Client($this->cfg['pagantis_public_key'], $this->cfg['pagantis_private_key']);
147
            $this->pagantisOrder = $this->orderClient->getOrder($this->pagantisOrderId);
148
        } catch (\Exception $e) {
149
            throw new OrderNotFoundException();
150
        }
151
    }
152
153
    /**
154
     * @throws AlreadyProcessedException
155
     * @throws WrongStatusException
156
     */
157
    private function checkOrderStatus()
158
    {
159
        try {
160
            $this->checkPagantisStatus(array('AUTHORIZED'));
161
        } catch (\Exception $e) {
162
            if ($this->woocommerceOrderId!='') {
163
                throw new AlreadyProcessedException();
164
            } else {
165
                if ($this->pagantisOrder instanceof \Pagantis\OrdersApiClient\Model\Order) {
166
                    $status = $this->pagantisOrder->getStatus();
167
                } else {
168
                    $status = '-';
169
                }
170
                throw new WrongStatusException($status);
171
            }
172
        }
173
    }
174
175
    /**
176
     * @throws AlreadyProcessedException
177
     */
178
    private function checkMerchantOrderStatus()
179
    {
180
        $validStatus   = array('on-hold', 'pending', 'failed');
181
        $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

181
        $isValidStatus = /** @scrutinizer ignore-call */ apply_filters(
Loading history...
182
            'woocommerce_valid_order_statuses_for_payment_complete',
183
            $validStatus,
184
            $this
185
        );
186
187
        if (!$this->woocommerceOrder->has_status($isValidStatus)) {
188
            throw new AlreadyProcessedException();
189
        }
190
    }
191
192
    /**
193
     * @throws AmountMismatchException
194
     */
195
    private function validateAmount()
196
    {
197
        $pagantisAmount = $this->pagantisOrder->getShoppingCart()->getTotalAmount();
198
        $wcAmount = intval(strval(100 * $this->woocommerceOrder->get_total()));
199
        if ($pagantisAmount != $wcAmount) {
200
            throw new AmountMismatchException($pagantisAmount, $wcAmount);
201
        }
202
    }
203
204
    /**
205
     * @throws Exception
206
     */
207
    private function processMerchantOrder()
208
    {
209
        $this->saveOrder();
210
        $this->updateBdInfo();
211
    }
212
213
    /**
214
     * @return false|string
215
     * @throws UnknownException
216
     */
217
    private function confirmPagantisOrder()
218
    {
219
        try {
220
            $this->pagantisOrder = $this->orderClient->confirmOrder($this->pagantisOrderId);
221
        } catch (\Exception $e) {
222
            throw new UnknownException($e->getMessage());
223
        }
224
225
        $jsonResponse = new JsonSuccessResponse();
226
        return $jsonResponse->toJson();
227
    }
228
    /**
229
     * UTILS FUNCTIONS
230
     */
231
    /** STEP 1 CC - Check concurrency */
232
    /**
233
     * Check if orders table exists
234
     */
235
    private function checkDbTable()
236
    {
237
        global $wpdb;
238
        $tableName = $wpdb->prefix.self::ORDERS_TABLE;
239
240
        if ($wpdb->get_var("SHOW TABLES LIKE '$tableName'") != $tableName) {
241
            $charset_collate = $wpdb->get_charset_collate();
242
            $sql             = "CREATE TABLE $tableName (id int, order_id varchar(50), wc_order_id varchar(50), 
243
                  UNIQUE KEY id (id)) $charset_collate";
244
245
            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...
246
            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

246
            /** @scrutinizer ignore-call */ dbDelta($sql);
Loading history...
247
        }
248
    }
249
250
    /**
251
     * Check if logs table exists
252
     */
253
    private function checkDbLogTable()
254
    {
255
        global $wpdb;
256
        $tableName = $wpdb->prefix.self::LOGS_TABLE;
257
258
        if ($wpdb->get_var("SHOW TABLES LIKE '$tableName'") != $tableName) {
259
            $charset_collate = $wpdb->get_charset_collate();
260
            $sql = "CREATE TABLE $tableName ( id int NOT NULL AUTO_INCREMENT, log text NOT NULL, 
261
                    createdAt timestamp DEFAULT CURRENT_TIMESTAMP, UNIQUE KEY id (id)) $charset_collate";
262
263
            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...
264
            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

264
            /** @scrutinizer ignore-call */ dbDelta($sql);
Loading history...
265
        }
266
        return;
267
    }
268
269
    /** STEP 2 GMO - Get Merchant Order */
270
    /** STEP 3 GPOI - Get Pagantis OrderId */
271
    /** STEP 4 GPO - Get Pagantis Order */
272
    /** STEP 5 COS - Check Order Status */
273
    /**
274
     * @param $statusArray
275
     *
276
     * @throws \Exception
277
     */
278
    private function checkPagantisStatus($statusArray)
279
    {
280
        $pagantisStatus = array();
281
        foreach ($statusArray as $status) {
282
            $pagantisStatus[] = constant("\Pagantis\OrdersApiClient\Model\Order::STATUS_$status");
283
        }
284
285
        if ($this->pagantisOrder instanceof \Pagantis\OrdersApiClient\Model\Order) {
286
            $payed = in_array($this->pagantisOrder->getStatus(), $pagantisStatus);
287
            if (!$payed) {
288
                if ($this->pagantisOrder instanceof \Pagantis\OrdersApiClient\Model\Order) {
0 ignored issues
show
introduced by
$this->pagantisOrder is always a sub-type of Pagantis\OrdersApiClient\Model\Order.
Loading history...
289
                    $status = $this->pagantisOrder->getStatus();
290
                } else {
291
                    $status = '-';
292
                }
293
                throw new WrongStatusException($status);
294
            }
295
        } else {
296
            throw new OrderNotFoundException();
297
        }
298
    }
299
    /** STEP 6 CMOS - Check Merchant Order Status */
300
    /** STEP 7 VA - Validate Amount */
301
    /** STEP 8 PMO - Process Merchant Order */
302
    /**
303
     * @throws \Exception
304
     */
305
    private function saveOrder()
306
    {
307
        global $woocommerce;
308
        $paymentResult = $this->woocommerceOrder->payment_complete();
309
        if ($paymentResult) {
310
            $this->woocommerceOrder->add_order_note("Notification received via $this->origin");
311
            $this->woocommerceOrder->reduce_order_stock();
312
            $this->woocommerceOrder->save();
313
314
            $woocommerce->cart->empty_cart();
315
            sleep(3);
316
        } else {
317
            throw new UnknownException('Order can not be saved');
318
        }
319
    }
320
321
    /**
322
     * Save the merchant order_id with the related identification
323
     */
324
    private function updateBdInfo()
325
    {
326
        global $wpdb;
327
328
        $this->checkDbTable();
329
        $tableName = $wpdb->prefix.self::ORDERS_TABLE;
330
331
        $wpdb->update(
332
            $tableName,
333
            array('wc_order_id'=>$this->woocommerceOrderId),
334
            array('id' => $this->woocommerceOrderId),
335
            array('%s'),
336
            array('%d')
337
        );
338
    }
339
340
    /** STEP 9 CPO - Confirmation Pagantis Order */
341
    private function rollbackMerchantOrder()
342
    {
343
        $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

343
        $this->woocommerceOrder->update_status('pending', /** @scrutinizer ignore-call */ __('Pending payment', 'woocommerce'));
Loading history...
344
    }
345
346
    /**
347
     * @param $exceptionMessage
348
     *
349
     * @throws \Zend_Db_Exception
350
     */
351
    private function insertLog($exception)
352
    {
353
        global $wpdb;
354
355
        if ($exception instanceof \Exception) {
356
            $this->checkDbLogTable();
357
            $logEntry= new LogEntry();
358
            $logEntryJson = $logEntry->error($exception)->toJson();
359
360
            $tableName = $wpdb->prefix.self::LOGS_TABLE;
361
            $wpdb->insert($tableName, array('log' => $logEntryJson));
362
        }
363
    }
364
365
    /**
366
     * GETTERS & SETTERS
367
     */
368
369
    /**
370
     * @return mixed
371
     */
372
    public function getOrigin()
373
    {
374
        return $this->origin;
375
    }
376
377
    /**
378
     * @param mixed $origin
379
     */
380
    public function setOrigin($origin)
381
    {
382
        $this->origin = $origin;
383
    }
384
}
385