Skip to content

Commit 89c694b

Browse files
authored
Merge pull request #9 from khipu/heads/2.5
2.5
2 parents c4c67fb + 136db42 commit 89c694b

File tree

6 files changed

+188
-177
lines changed

6 files changed

+188
-177
lines changed

Controller/Payment/Callback.php

Lines changed: 122 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,22 +8,33 @@
88
use Magento\Framework\App\CsrfAwareActionInterface;
99
use Magento\Framework\App\RequestInterface;
1010
use Magento\Framework\App\Request\InvalidRequestException;
11+
use Magento\Framework\Controller\Result\JsonFactory;
12+
use Magento\Framework\App\Config\ScopeConfigInterface;
13+
use Magento\Sales\Model\Order\Email\Sender\OrderSender;
1114

1215
class Callback extends Action implements CsrfAwareActionInterface
1316
{
1417
protected $order;
1518
protected $khipuPayment;
19+
protected $resultJsonFactory;
20+
protected $scopeConfig;
21+
protected $orderSender;
1622

1723
public function __construct(
1824
Context $context,
1925
Order $order,
20-
Simplified $khipuPayment
26+
Simplified $khipuPayment,
27+
JsonFactory $resultJsonFactory,
28+
ScopeConfigInterface $scopeConfig,
29+
OrderSender $orderSender
2130
)
2231
{
2332
parent::__construct($context);
24-
2533
$this->order = $order;
2634
$this->khipuPayment = $khipuPayment;
35+
$this->resultJsonFactory = $resultJsonFactory;
36+
$this->scopeConfig = $scopeConfig;
37+
$this->orderSender = $orderSender;
2738
}
2839

2940
public function createCsrfValidationException(RequestInterface $request): ?InvalidRequestException
@@ -36,22 +47,119 @@ public function validateForCsrf(RequestInterface $request): ?bool
3647
return true;
3748
}
3849

39-
/**
40-
* Default customer account page
41-
*
42-
* @return void
43-
*/
4450
public function execute()
4551
{
46-
$order = $this->order->loadByIncrementId($this->getRequest()->getParam('order_id'));
52+
$secret = $this->scopeConfig->getValue('payment/simplified/merchant_secret');
53+
54+
if (!$secret) {
55+
throw new \Exception('Missing secret in configuration');
56+
}
57+
$raw_post = file_get_contents('php://input');
58+
$signature = $_SERVER['HTTP_X_KHIPU_SIGNATURE'] ?? '';
59+
60+
if (!$signature) {
61+
return $this->resultJsonFactory->create()->setData(['error' => 'Missing signature header'])->setStatusHeader(400);
62+
}
63+
64+
$notificationData = json_decode($raw_post, true);
65+
4766
try {
48-
$this->khipuPayment->validateKhipuCallback($order, $this->getRequest()->getPost()['notification_token'],
49-
$this->getRequest()->getPost()['api_version']);
67+
$this->verifyNotification($raw_post, $signature, $secret);
5068
} catch (\Exception $e) {
51-
$this->getResponse()->setStatusCode(\Magento\Framework\App\Response\Http::STATUS_CODE_400);
52-
$this->getResponse()->setContent($e->getMessage());
53-
return;
69+
return $this->resultJsonFactory->create()->setData(['error' => $e->getMessage()])->setStatusHeader(400);
70+
}
71+
72+
if (isset($notificationData['payment_id'])) {
73+
$order = $this->order->loadByIncrementId($notificationData['transaction_id']);
74+
if ($order->getId()) {
75+
try {
76+
$this->validateKhipuCallback($order, $notificationData, '3.0');
77+
} catch (\Exception $e) {
78+
return $this->resultJsonFactory->create()->setData(['error' => $e->getMessage()])->setStatusHeader(400);
79+
}
80+
return $this->resultJsonFactory->create()->setData(['success' => true])->setStatusHeader(200);
81+
} else {
82+
return $this->resultJsonFactory->create()->setData(['error' => 'Order not found'])->setStatusHeader(404);
83+
}
84+
} else {
85+
return $this->resultJsonFactory->create()->setData(['error' => 'Invalid notification data'])->setStatusHeader(400);
5486
}
55-
$this->getResponse()->setBody('OK');
87+
}
88+
89+
private function verifyNotification($notificationData, $signatureHeader, $secret)
90+
{
91+
$signature_parts = explode(',', $signatureHeader);
92+
$t_value = '';
93+
$s_value = '';
94+
foreach ($signature_parts as $part) {
95+
[$key, $value] = explode('=', $part);
96+
if ($key === 't') {
97+
$t_value = $value;
98+
} elseif ($key === 's') {
99+
$s_value = $value;
100+
}
101+
}
102+
103+
$to_hash = $t_value . '.' . $notificationData;
104+
$hmac_signature = hash_hmac('sha256', $to_hash, $secret, true);
105+
$hmac_base64 = base64_encode($hmac_signature);
106+
107+
return hash_equals($hmac_base64, $s_value);
108+
}
109+
110+
111+
public function validateKhipuCallback(Order $order, $notificationData, $apiVersion)
112+
{
113+
if (!$order || !$order->getIncrementId()) {
114+
throw new \Exception('Order #' . $_REQUEST['order_id'] . ' does not exist');
115+
}
116+
117+
if ($apiVersion != '3.0') {
118+
throw new \Exception('Invalid notification API version.');
119+
}
120+
121+
if ($notificationData['receiver_id'] != $this->scopeConfig->getValue('payment/simplified/merchant_id')) {
122+
throw new \Exception('Invalid receiver ID');
123+
}
124+
125+
if ($notificationData['custom'] != $order->getPayment()->getAdditionalInformation('khipu_order_token')) {
126+
throw new \Exception('Invalid transaction ID');
127+
}
128+
129+
if ($notificationData['amount'] != number_format($order->getGrandTotal(),
130+
$this->khipuPayment->getDecimalPlaces($order->getOrderCurrencyCode()), '.', '')
131+
) {
132+
throw new \Exception('Amount mismatch');
133+
}
134+
135+
if ($notificationData['currency'] != $order->getOrderCurrencyCode()) {
136+
throw new \Exception('Currency mismatch');
137+
}
138+
139+
$responseTxt = 'Pago Khipu Aceptado<br>';
140+
$responseTxt .= 'TransactionId: ' . $notificationData['transaction_id'] . '<br>';
141+
$responseTxt .= 'PaymentId: ' . $notificationData['payment_id'] . '<br>';
142+
$responseTxt .= 'Subject: ' . $notificationData['subject'] . '<br>';
143+
$responseTxt .= 'Amount: ' . $notificationData['amount'] .' '.$notificationData['currency'] .'<br>';
144+
$responseTxt .= 'Body: ' . $notificationData['body'] . '<br>';
145+
$responseTxt .= 'Bank: ' . $notificationData['bank'] . '<br>';
146+
$responseTxt .= 'Bank Account Number: ' . $notificationData['bank_account_number'] . '<br>';
147+
$responseTxt .= 'Payer Name: ' . $notificationData['payer_name'] . '<br>';
148+
$responseTxt .= 'Payer Email: ' . $notificationData['payer_email'] . '<br>';
149+
$responseTxt .= 'Personal Identifier: ' . $notificationData['personal_identifier'] . '<br>';
150+
151+
$invoice = $order->prepareInvoice();
152+
$invoice->register();
153+
$invoice->save();
154+
155+
$paymentCompleteStatus = $this->scopeConfig->getValue('payment/simplified/payment_complete_status');
156+
157+
$order->setState($paymentCompleteStatus, false, "Pago Realizado con Khipu", true);
158+
$order->setStatus($order->getConfig()->getStateDefaultStatus($paymentCompleteStatus));
159+
$order->setIsCustomerNotified(true);
160+
$order->addStatusToHistory($paymentCompleteStatus, $responseTxt);
161+
$order->save();
162+
163+
$this->orderSender->send($order);
56164
}
57165
}

0 commit comments

Comments
 (0)