Completed
Push — master ( 1137b9...97c77e )
by
unknown
20s queued 11s
created

Controller/Notify/Index.php (2 issues)

1
<?php
2
3
namespace DigitalOrigin\Pmt\Controller\Notify;
4
5
use Magento\Quote\Model\QuoteManagement;
6
use Magento\Quote\Api\Data\PaymentInterface;
7
use Magento\Sales\Api\OrderRepositoryInterface;
8
use Magento\Quote\Model\Quote;
9
use Magento\Quote\Model\QuoteRepository;
10
use Magento\Framework\App\Action\Context;
11
use Magento\Framework\App\Action\Action;
12
use PagaMasTarde\OrdersApiClient\Client;
13
use DigitalOrigin\Pmt\Logger\Logger;
14
use DigitalOrigin\Pmt\Helper\Config;
15
use Magento\Framework\App\ResourceConnection;
16
use Magento\Checkout\Model\Session;
17
18
/**
19
 * Class Index
20
 * @package DigitalOrigin\Pmt\Controller\Notify
21
 */
22
class Index extends Action
23
{
24
    /** Orders tablename */
25
    const ORDERS_TABLE = 'cart_process';
26
27
    /** Concurrency tablename */
28
    const CONCURRENCY_TABLE = 'pmt_orders';
29
30
    /** Payment code */
31
    const PAYMENT_METHOD = 'paylater';
32
33
    /**
34
     * EXCEPTION RESPONSES
35
     */
36
    const NO_QUOTE = 'QuoteId not found';
37
    const ALREADY_PROCESSED = 'Cart already processed.';
38
    const NO_ORDERID = 'We can not get the PagaMasTarde identification in database.';
39
    const WRONG_AMOUNT = 'Wrong order amount';
40
    const WRONG_STATUS = 'Invalid Pmt status';
41
    const NO_MGID = 'We can not get the Magento order identification';
42
43
    /** @var QuoteManagement */
44
    protected $quoteManagement;
45
46
    /** @var PaymentInterface $paymentInterface */
47
    protected $paymentInterface;
48
49
    /** @var OrderRepositoryInterface $orderRepositoryInterface */
50
    protected $orderRepositoryInterface;
51
52
    /** @var Quote $quote */
53
    protected $quote;
54
55
    /** @var QuoteRepository $quoteRepository */
56
    protected $quoteRepository;
57
58
    /** @var Logger $logger */
59
    protected $logger;
60
61
    /** @var mixed $config */
62
    protected $config;
63
64
    /** @var mixed $quoteId */
65
    protected $quoteId;
66
67
    /** @var Array_ $notifyResult */
68
    protected $notifyResult;
69
70
    /** @var mixed $magentoOrderId */
71
    protected $magentoOrderId;
72
73
    /** @var mixed $pmtOrder */
74
    protected $pmtOrder;
75
76
    /** @var ResourceConnection $dbObject */
77
    protected $dbObject;
78
79
    /** @var Session $checkoutSession */
80
    protected $checkoutSession;
81
82
    /**
83
     * Index constructor.
84
     *
85
     * @param Context                  $context
86
     * @param Quote                    $quote
87
     * @param Logger                   $logger
88
     * @param QuoteManagement          $quoteManagement
89
     * @param PaymentInterface         $paymentInterface
90
     * @param Config                   $config
91
     * @param QuoteRepository          $quoteRepository
92
     * @param OrderRepositoryInterface $orderRepositoryInterface
93
     * @param ResourceConnection       $dbObject
94
     * @param Session                  $checkoutSession
95
     */
96
    public function __construct(
97
        Context $context,
98
        Quote $quote,
99
        Logger $logger,
100
        QuoteManagement $quoteManagement,
101
        PaymentInterface $paymentInterface,
102
        Config $config,
103
        QuoteRepository $quoteRepository,
104
        OrderRepositoryInterface $orderRepositoryInterface,
105
        ResourceConnection $dbObject,
106
        Session $checkoutSession
107
    ) {
108
        parent::__construct($context);
109
        $this->quote = $quote;
110
        $this->logger = $logger;
111
        $this->quoteManagement = $quoteManagement;
112
        $this->paymentInterface = $paymentInterface;
113
        $this->config = $config->getConfig();
114
        $this->quoteRepository = $quoteRepository;
115
        $this->orderRepositoryInterface = $orderRepositoryInterface;
116
        $this->dbObject = $dbObject;
117
        $this->checkoutSession = $checkoutSession;
118
        $this->notifyResult = array('notification_message'=>'','notification_error'=>true);
0 ignored issues
show
Documentation Bug introduced by
It seems like array('notification_mess...ication_error' => true) of type array<string,string|true> is incompatible with the declared type DigitalOrigin\Pmt\Controller\Notify\Array_ of property $notifyResult.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
119
    }
120
121
    /**
122
     * Main function
123
     *
124
     * @return \Magento\Framework\App\ResponseInterface|\Magento\Framework\Controller\ResultInterface|void
125
     */
126
    public function execute()
127
    {
128
        try {
129
            $this->quoteId = $this->getQuoteId();
130
            if ($this->unblockConcurrency()) {
131
                if ($this->blockConcurrency()) {
132
                    $this->validateOrder();
133
                }
134
            }
135
        } catch (\Exception $exception) {
136
            $this->notifyResult['notification_message'] = $exception->getMessage();
137
            $this->logger->info(__METHOD__.'=>'.$exception->getMessage());
138
        }
139
140
        $this->unblockConcurrency(true);
141
        if ($_SERVER['REQUEST_METHOD'] == 'POST') {
142
            $response = json_encode(array(
143
                'timestamp' => time(),
144
                'order_id' => $this->magentoOrderId,
145
                'result' => (!$this->notifyResult['notification_error']) ? 'success' : 'failed',
146
                'result_description' => $this->notifyResult['notification_message']
147
            ));
148
            if ($this->notifyResult['notification_error']) {
149
                header('HTTP/1.1 400 Bad Request', true, 400);
150
            } else {
151
                header('HTTP/1.1 200 Ok', true, 200);
152
            }
153
            header('Content-Type: application/json', true);
154
            header('Content-Length: ' . strlen($response));
155
            echo ($response);
156
            exit();
157
        } else {
158
            $returnUrl = $this->getRedirectUrl();
159
            $this->_redirect($returnUrl);
160
        }
161
    }
162
163
    /**
164
     * @return mixed
165
     * @throws \Exception
166
     */
167
    private function getQuoteId()
168
    {
169
        if ($this->getRequest()->getParam('quoteId')=='') {
170
            $this->notifyResult['notification_error'] = false;
171
            throw new \Exception(self::NO_QUOTE);
172
        }
173
174
        return $this->getRequest()->getParam('quoteId');
175
    }
176
177
    /**
178
     * @throws \Httpful\Exception\ConnectionErrorException
179
     * @throws \Magento\Framework\Exception\CouldNotSaveException
180
     * @throws \Magento\Framework\Exception\NoSuchEntityException
181
     * @throws \PagaMasTarde\OrdersApiClient\Exception\HttpException
182
     * @throws \PagaMasTarde\OrdersApiClient\Exception\ValidationException
183
     */
184
    private function validateOrder()
185
    {
186
        $this->getMagentoOrderId();
187
        $pmtOrderId = $this->getPmtOrderId();
188
        $orderClient = new Client($this->config['public_key'], $this->config['secret_key']);
189
        $this->pmtOrder = $orderClient->getOrder($pmtOrderId);
190
        $this->checkPmtStatus(array('CONFIRMED','AUTHORIZED'));
191
192
        $this->quote = $this->quoteRepository->get($this->quoteId);
193
        $this->checkCartStatus();
194
        $this->comparePrices();
195
        $this->magentoOrderId = $this->saveOrder();
196
        $this->updateBdInfo();
197
        $this->pmtOrder = $orderClient->confirmOrder($pmtOrderId);
198
        $this->checkPmtStatus(array('CONFIRMED'));
199
        $this->notifyResult['notification_error'] = false;
200
201
        return;
202
    }
203
204
    /**
205
     * @return mixed
206
     * @throws \Exception
207
     */
208
    private function getPmtOrderId()
209
    {
210
        $dbConnection = $this->dbObject->getConnection();
211
        $tableName    = $this->dbObject->getTableName(self::ORDERS_TABLE);
212
        $query        = "select order_id from $tableName where id='$this->quoteId'";
213
        $queryResult  = $dbConnection->fetchRow($query);
214
215
        if ($queryResult['order_id'] == '') {
216
            $this->notifyResult['notification_error'] = false;
217
            throw new \Exception(self::NO_ORDERID);
218
        }
219
        return $queryResult['order_id'];
220
    }
221
222
    private function getMagentoOrderId()
223
    {
224
        $dbConnection = $this->dbObject->getConnection();
225
        $tableName    = $this->dbObject->getTableName(self::ORDERS_TABLE);
226
        $query        = "select mg_order_id from $tableName where id='$this->quoteId'";
227
        $queryResult  = $dbConnection->fetchRow($query);
228
229
        if ($queryResult['mg_order_id'] != '') {
230
            $this->magentoOrderId = $queryResult['mg_order_id'];
231
            $this->notifyResult['notification_error'] = false;
232
            throw new \Exception(self::ALREADY_PROCESSED);
233
        }
234
235
        return;
236
    }
237
238
    /**
239
     * @param $statusArray
240
     *
241
     * @throws \Exception
242
     */
243
    private function checkPmtStatus($statusArray)
244
    {
245
        $pmtStatus = array();
246
        foreach ($statusArray as $status) {
247
            $pmtStatus[] = constant("\PagaMasTarde\OrdersApiClient\Model\Order::STATUS_$status");
248
        }
249
250
        $payed = in_array($this->pmtOrder->getStatus(), $pmtStatus);
251
        if (!$payed) {
252
            $this->notifyResult['notification_error'] = true;
253
            throw new \Exception(self::WRONG_STATUS."=>".$this->pmtOrder->getStatus());
254
        }
255
256
        return;
257
    }
258
259
    /**
260
     * @return bool
261
     * @throws \Exception
262
     */
263
    private function checkCartStatus()
264
    {
265
        if ($this->quote->getIsActive()=='0') {
266
            $this->magentoOrderId = $this->getMgOrderId();
267
            $this->notifyResult['notification_error'] = false;
268
            throw new \Exception(self::ALREADY_PROCESSED);
269
        }
270
        return true;
271
    }
272
273
    /**
274
     * @throws \Exception
275
     */
276
    private function comparePrices()
277
    {
278
        $grandTotal = $this->quote->getGrandTotal();
279
        if ($this->pmtOrder->getShoppingCart()->getTotalAmount() != intval(strval(100 * $grandTotal))) {
280
            $this->notifyResult['notification_error'] = true;
281
            throw new \Exception(self::WRONG_AMOUNT);
282
        }
283
        return;
284
    }
285
286
    /**
287
     * @return int|mixed
288
     * @throws \Magento\Framework\Exception\CouldNotSaveException
289
     */
290
    private function saveOrder()
291
    {
292
        $this->paymentInterface->setMethod(self::PAYMENT_METHOD);
293
        return $this->quoteManagement->placeOrder($this->quoteId, $this->paymentInterface);
294
    }
295
296
    /**
297
     * @return string
298
     */
299
    private function getRedirectUrl()
300
    {
301
        $returnUrl = 'checkout/#payment';
302
        if ($this->magentoOrderId!='') {
303
            /** @var Order $order */
304
            $this->magentoOrder = $this->orderRepositoryInterface->get($this->magentoOrderId);
0 ignored issues
show
Bug Best Practice introduced by
The property magentoOrder does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
305
            if (!$this->_objectManager->get(\Magento\Checkout\Model\Session\SuccessValidator::class)->isValid()) {
306
                $this->checkoutSession
307
                    ->setLastOrderId($this->magentoOrderId)
308
                    ->setLastRealOrderId($this->magentoOrder->getIncrementId())
309
                    ->setLastQuoteId($this->quoteId)
310
                    ->setLastSuccessQuoteId($this->quoteId)
311
                    ->setLastOrderStatus($this->magentoOrder->getStatus());
312
            }
313
314
            //Magento status flow => https://docs.magento.com/m2/ce/user_guide/sales/order-status-workflow.html
315
            //Order Workflow => https://docs.magento.com/m2/ce/user_guide/sales/order-workflow.html
316
            $orderStatus       = strtolower($this->magentoOrder->getStatus());
317
            $acceptedStatus     = array('processing', 'completed');
318
            if (in_array($orderStatus, $acceptedStatus)) {
319
                if ($this->config['ok_url'] != '') {
320
                    $returnUrl = $this->config['ok_url'];
321
                } else {
322
                    $returnUrl = '/checkout/onepage/success';
323
                }
324
            } else {
325
                if ($this->config['ko_url'] != '') {
326
                    $returnUrl = $this->config['ko_url'];
327
                } else {
328
                    $returnUrl = 'checkout/#payment';
329
                }
330
            }
331
        }
332
        return $returnUrl;
333
    }
334
335
    /**
336
     * @return mixed
337
     */
338
    private function checkDbTable()
339
    {
340
        $dbConnection = $this->dbObject->getConnection();
341
        $tableName    = $this->dbObject->getTableName(self::CONCURRENCY_TABLE);
342
        $query = "CREATE TABLE IF NOT EXISTS $tableName(`id` int not null,`timestamp` int not null,PRIMARY KEY (`id`))";
343
        return $dbConnection->query($query);
344
    }
345
346
    /**
347
     * @param bool $mode
348
     *
349
     * @return bool
350
     */
351
    private function unblockConcurrency($mode = false)
352
    {
353
        try {
354
            $this->checkDbTable();
355
            $dbConnection = $this->dbObject->getConnection();
356
            $tableName    = $this->dbObject->getTableName(self::CONCURRENCY_TABLE);
357
            if ($mode == false) {
358
                $dbConnection->delete($tableName, "timestamp<".(time() - 5));
359
            } elseif ($this->quoteId!='') {
360
                $dbConnection->delete($tableName, "id=".$this->quoteId);
361
            }
362
        } catch (Exception $exception) {
363
            $this->logger->info(__METHOD__.'=>'.$exception->getMessage());
364
            $this->notifyResult['notification_message'] = $exception->getMessage();
365
            $this->notifyResult['notification_error'] = true;
366
            return false;
367
        }
368
        return true;
369
    }
370
371
    /**
372
     * @return bool
373
     */
374
    private function blockConcurrency()
375
    {
376
        try {
377
            $dbConnection = $this->dbObject->getConnection();
378
            $tableName    = $this->dbObject->getTableName(self::CONCURRENCY_TABLE);
379
            $dbConnection->insert($tableName, array('id'=>$this->quoteId, 'timestamp'=>time()));
380
        } catch (\Exception $exception) {
381
            $this->logger->info(__METHOD__.'=>'.$exception->getMessage());
382
            $this->notifyResult['notification_message'] = 'Validation in progress, try again later';
383
            $this->notifyResult['notification_error'] = true;
384
            return false;
385
        }
386
        return true;
387
    }
388
389
    /**
390
     * @return mixed
391
     * @throws \Exception
392
     */
393
    private function updateBdInfo()
394
    {
395
        $dbConnection = $this->dbObject->getConnection();
396
        $tableName    = $this->dbObject->getTableName(self::ORDERS_TABLE);
397
        $pmtOrderId   = $this->pmtOrder->getId();
398
        $dbConnection->update(
399
            $tableName,
400
            array('mg_order_id'=>$this->magentoOrderId),
401
            "order_id='$pmtOrderId' and id='$this->quoteId'"
402
        );
403
    }
404
405
    /**
406
     * @return mixed
407
     * @throws \Exception
408
     */
409
    private function getMgOrderId()
410
    {
411
        $dbConnection = $this->dbObject->getConnection();
412
        $tableName    = $this->dbObject->getTableName(self::ORDERS_TABLE);
413
        $pmtOrderId   = $this->pmtOrder->getId();
414
        $query        = "select mg_order_id from $tableName where id='$this->quoteId' and order_id='$pmtOrderId'";
415
        $queryResult  = $dbConnection->fetchRow($query);
416
417
        if ($queryResult['mg_order_id']=='') {
418
            $this->notifyResult['notification_error'] = false;
419
            throw new \Exception(self::NO_MGID);
420
        }
421
        return $queryResult['mg_order_id'];
422
    }
423
}
424