Skip to content

Commit 3a576d3

Browse files
committed
Add Webhook handler to the module
1 parent db68b09 commit 3a576d3

6 files changed

Lines changed: 212 additions & 2 deletions

File tree

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
<?php
2+
3+
/**
4+
* Paystack Magento2 Module using \Magento\Payment\Model\Method\AbstractMethod
5+
* Copyright (C) 2019 Paystack.com
6+
*
7+
* This file is part of Pstk/Paystack.
8+
*
9+
* Pstk/Paystack is free software => you can redistribute it and/or modify
10+
* it under the terms of the GNU General Public License as published by
11+
* the Free Software Foundation, either version 3 of the License, or
12+
* (at your option) any later version.
13+
*
14+
* This program is distributed in the hope that it will be useful,
15+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
16+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17+
* GNU General Public License for more details.
18+
*
19+
* You should have received a copy of the GNU General Public License
20+
* along with this program. If not, see <http =>//www.gnu.org/licenses/>.
21+
*/
22+
23+
namespace Pstk\Paystack\Block\System\Config\Form\Field;
24+
25+
use Magento\Framework\Data\Form\Element\AbstractElement;
26+
use Magento\Store\Model\Store as Store;
27+
28+
/**
29+
* Backend system config datetime field renderer
30+
*
31+
* @api
32+
* @since 100.0.2
33+
*/
34+
class Webhook extends \Magento\Config\Block\System\Config\Form\Field
35+
{
36+
37+
/**
38+
* @param \Magento\Backend\Block\Template\Context $context
39+
* @param Store $store
40+
* @param array $data
41+
*/
42+
public function __construct(
43+
\Magento\Backend\Block\Template\Context $context,
44+
Store $store,
45+
array $data = []
46+
) {
47+
$this->store = $store;
48+
49+
parent::__construct($context, $data);
50+
}
51+
52+
/**
53+
* Returns element html
54+
*
55+
* @param AbstractElement $element
56+
* @return string
57+
*/
58+
protected function _getElementHtml(AbstractElement $element)
59+
{
60+
$webhookUrl = $this->store->getBaseUrl() . 'paystack/payment/webhook';
61+
$value = "You may login to <a target=\"_blank\" href=\"https://dashboard.paystack.co/#/settings/developer\">Paystack Developer Settings</a> to update your Webhook URL to:<br><br>"
62+
. "<strong style='color:red;'>$webhookUrl</strong>";
63+
64+
$element->setValue($webhookUrl);
65+
66+
return $value;
67+
}
68+
}

Controller/Payment/AbstractPaystackStandard.php

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,26 @@
2828
abstract class AbstractPaystackStandard extends \Magento\Framework\App\Action\Action {
2929

3030
protected $resultPageFactory;
31+
32+
/**
33+
*
34+
* @var \Magento\Sales\Api\OrderRepositoryInterface
35+
*/
3136
protected $orderRepository;
37+
38+
/**
39+
*
40+
* @var \Magento\Sales\Api\Data\OrderInterface
41+
*/
3242
protected $orderInterface;
3343
protected $checkoutSession;
3444
protected $method;
3545
protected $messageManager;
46+
47+
/**
48+
*
49+
* @var \Pstk\Paystack\Model\Ui\ConfigProvider
50+
*/
3651
protected $configProvider;
3752

3853
/**
@@ -45,6 +60,12 @@ abstract class AbstractPaystackStandard extends \Magento\Framework\App\Action\Ac
4560
* @var \Magento\Framework\Event\Manager
4661
*/
4762
protected $eventManager;
63+
64+
/**
65+
*
66+
* @var \Psr\Log\LoggerInterface
67+
*/
68+
protected $logger;
4869

4970
/**
5071
* Constructor
@@ -61,7 +82,8 @@ public function __construct(
6182
PaymentHelper $paymentHelper,
6283
\Magento\Framework\Message\ManagerInterface $messageManager,
6384
\Pstk\Paystack\Model\Ui\ConfigProvider $configProvider,
64-
\Magento\Framework\Event\Manager $eventManager
85+
\Magento\Framework\Event\Manager $eventManager,
86+
\Psr\Log\LoggerInterface $logger
6587
) {
6688
$this->resultPageFactory = $resultPageFactory;
6789
$this->orderRepository = $orderRepository;
@@ -71,6 +93,7 @@ public function __construct(
7193
$this->messageManager = $messageManager;
7294
$this->configProvider = $configProvider;
7395
$this->eventManager = $eventManager;
96+
$this->logger = $logger;
7497

7598
$this->paystack = $this->initPaystackPHP();
7699

Controller/Payment/Webhook.php

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
<?php
2+
3+
/**
4+
* Paystack Magento2 Module using \Magento\Payment\Model\Method\AbstractMethod
5+
* Copyright (C) 2019 Paystack.com
6+
*
7+
* This file is part of Pstk/Paystack.
8+
*
9+
* Pstk/Paystack is free software => you can redistribute it and/or modify
10+
* it under the terms of the GNU General Public License as published by
11+
* the Free Software Foundation, either version 3 of the License, or
12+
* (at your option) any later version.
13+
*
14+
* This program is distributed in the hope that it will be useful,
15+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
16+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17+
* GNU General Public License for more details.
18+
*
19+
* You should have received a copy of the GNU General Public License
20+
* along with this program. If not, see <http =>//www.gnu.org/licenses/>.
21+
*/
22+
23+
namespace Pstk\Paystack\Controller\Payment;
24+
25+
use Magento\Sales\Model\Order;
26+
use Magento\Framework\App\CsrfAwareActionInterface;
27+
28+
class Webhook extends AbstractPaystackStandard implements CsrfAwareActionInterface
29+
{
30+
31+
public function execute() {
32+
33+
// Retrieve the request's body and parse it as JSON
34+
$event = \Yabacon\Paystack\Event::capture();
35+
http_response_code(200);
36+
37+
/* It is a important to log all events received. Add code *
38+
* here to log the signature and body to db or file */
39+
$this->logger->debug("PAYSTACK_LOG: {$event->raw}");
40+
41+
/* Verify that the signature matches one of your keys */
42+
$secretKey = $this->configProvider->getSecretKeyArray();
43+
$owner = $event->discoverOwner($secretKey);
44+
45+
if (!$owner) {
46+
// None of the keys matched the event's signature
47+
die("auth failed");
48+
}
49+
50+
// Do something with $event->obj
51+
// Give value to your customer but don't give any output
52+
// Remember that this is a call from Paystack's servers and
53+
// Your customer is not seeing the response here at all
54+
switch ($event->obj->event) {
55+
// charge.success
56+
case 'charge.success':
57+
if ('success' === $event->obj->data->status) {
58+
$transactionDetails = $this->paystack->transaction->verify([
59+
'reference' => $event->obj->data->reference
60+
]);
61+
62+
$reference = $transactionDetails->data->reference;
63+
64+
$order = $this->orderInterface->loadByIncrementId($reference);
65+
66+
//if is popup mode, reference is generated by Paystack and we provided quoteId instead
67+
if((!$order || !$order->getId()) && isset($event->obj->data->metadata->quoteId)){
68+
69+
$objectManager = \Magento\Framework\App\ObjectManager::getInstance();
70+
$searchCriteriaBuilder = $objectManager->create('Magento\Framework\Api\SearchCriteriaBuilder');
71+
$searchCriteria = $searchCriteriaBuilder->addFilter('quote_id', $event->obj->data->metadata->quoteId, 'eq')->create();
72+
$items = $this->orderRepository->getList($searchCriteria);
73+
if($items->getTotalCount() == 1){
74+
$order = $items->getFirstItem();
75+
}
76+
77+
}
78+
79+
if ($order && $order->getId()) {
80+
// dispatch the `payment_verify_after` event to update the order status
81+
$this->eventManager->dispatch('paystack_payment_verify_after', [
82+
"paystack_order" => $order,
83+
]);
84+
die("success");
85+
}
86+
}
87+
break;
88+
}
89+
90+
die("failed");
91+
}
92+
93+
public function createCsrfValidationException(\Magento\Framework\App\RequestInterface $request): ?\Magento\Framework\App\Request\InvalidRequestException {
94+
return null;
95+
}
96+
97+
public function validateForCsrf(\Magento\Framework\App\RequestInterface $request): ?bool {
98+
return true;
99+
}
100+
101+
}

Model/Ui/ConfigProvider.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,5 +50,19 @@ public function getStore() {
5050
return $this->store;
5151
}
5252

53+
/**
54+
* Get secret key for webhook process
55+
*
56+
* @return array
57+
*/
58+
public function getSecretKeyArray(){
59+
$data = ["live" => $this->method->getConfigData('live_secret_key')];
60+
if ($this->method->getConfigData('test_mode')) {
61+
$data = ["test" => $this->method->getConfigData('test_secret_key')];
62+
}
63+
64+
return $data;
65+
}
66+
5367

5468
}

Observer/ObserverAfterPaymentVerify.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public function execute(\Magento\Framework\Event\Observer $observer)
3131
/** @var \Magento\Sales\Model\Order $order **/
3232
$order = $observer->getPaystackOrder();
3333

34-
if ($order) {
34+
if ($order && $order->getStatus() == "pending") {
3535
// sets the status to processing since payment has been received
3636
$order->setState(Order::STATE_PROCESSING)
3737
->addStatusToHistory(Order::STATE_PROCESSING, __("Paystack Payment Verified and Order is being processed"), true)

etc/adminhtml/system.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@
77
<comment>
88
<![CDATA[<a href="https://dashboard.paystack.com/#/signup" target="_blank">Click here to sign up for Paystack account</a>]]>
99
</comment>
10+
<field id="default_webhook" translate="label comment" type="label" sortOrder="0" showInDefault="1" showInWebsite="1" showInStore="0">
11+
<label>Webhook URL</label>
12+
<frontend_model>Pstk\Paystack\Block\System\Config\Form\Field\Webhook</frontend_model>
13+
</field>
1014
<field id="active" translate="label" type="select" sortOrder="1" showInDefault="1" showInWebsite="1" showInStore="0">
1115
<label>Enabled</label>
1216
<source_model>Magento\Config\Model\Config\Source\Yesno</source_model>

0 commit comments

Comments
 (0)