diff --git a/Controller/Payment/Callback.php b/Controller/Payment/Callback.php
index 82c2d08..e288011 100644
--- a/Controller/Payment/Callback.php
+++ b/Controller/Payment/Callback.php
@@ -8,22 +8,33 @@
use Magento\Framework\App\CsrfAwareActionInterface;
use Magento\Framework\App\RequestInterface;
use Magento\Framework\App\Request\InvalidRequestException;
+use Magento\Framework\Controller\Result\JsonFactory;
+use Magento\Framework\App\Config\ScopeConfigInterface;
+use Magento\Sales\Model\Order\Email\Sender\OrderSender;
class Callback extends Action implements CsrfAwareActionInterface
{
protected $order;
protected $khipuPayment;
+ protected $resultJsonFactory;
+ protected $scopeConfig;
+ protected $orderSender;
public function __construct(
Context $context,
Order $order,
- Simplified $khipuPayment
+ Simplified $khipuPayment,
+ JsonFactory $resultJsonFactory,
+ ScopeConfigInterface $scopeConfig,
+ OrderSender $orderSender
)
{
parent::__construct($context);
-
$this->order = $order;
$this->khipuPayment = $khipuPayment;
+ $this->resultJsonFactory = $resultJsonFactory;
+ $this->scopeConfig = $scopeConfig;
+ $this->orderSender = $orderSender;
}
public function createCsrfValidationException(RequestInterface $request): ?InvalidRequestException
@@ -36,22 +47,119 @@ public function validateForCsrf(RequestInterface $request): ?bool
return true;
}
- /**
- * Default customer account page
- *
- * @return void
- */
public function execute()
{
- $order = $this->order->loadByIncrementId($this->getRequest()->getParam('order_id'));
+ $secret = $this->scopeConfig->getValue('payment/simplified/merchant_secret');
+
+ if (!$secret) {
+ throw new \Exception('Missing secret in configuration');
+ }
+ $raw_post = file_get_contents('php://input');
+ $signature = $_SERVER['HTTP_X_KHIPU_SIGNATURE'] ?? '';
+
+ if (!$signature) {
+ return $this->resultJsonFactory->create()->setData(['error' => 'Missing signature header'])->setStatusHeader(400);
+ }
+
+ $notificationData = json_decode($raw_post, true);
+
try {
- $this->khipuPayment->validateKhipuCallback($order, $this->getRequest()->getPost()['notification_token'],
- $this->getRequest()->getPost()['api_version']);
+ $this->verifyNotification($raw_post, $signature, $secret);
} catch (\Exception $e) {
- $this->getResponse()->setStatusCode(\Magento\Framework\App\Response\Http::STATUS_CODE_400);
- $this->getResponse()->setContent($e->getMessage());
- return;
+ return $this->resultJsonFactory->create()->setData(['error' => $e->getMessage()])->setStatusHeader(400);
+ }
+
+ if (isset($notificationData['payment_id'])) {
+ $order = $this->order->loadByIncrementId($notificationData['transaction_id']);
+ if ($order->getId()) {
+ try {
+ $this->validateKhipuCallback($order, $notificationData, '3.0');
+ } catch (\Exception $e) {
+ return $this->resultJsonFactory->create()->setData(['error' => $e->getMessage()])->setStatusHeader(400);
+ }
+ return $this->resultJsonFactory->create()->setData(['success' => true])->setStatusHeader(200);
+ } else {
+ return $this->resultJsonFactory->create()->setData(['error' => 'Order not found'])->setStatusHeader(404);
+ }
+ } else {
+ return $this->resultJsonFactory->create()->setData(['error' => 'Invalid notification data'])->setStatusHeader(400);
}
- $this->getResponse()->setBody('OK');
+ }
+
+ private function verifyNotification($notificationData, $signatureHeader, $secret)
+ {
+ $signature_parts = explode(',', $signatureHeader);
+ $t_value = '';
+ $s_value = '';
+ foreach ($signature_parts as $part) {
+ [$key, $value] = explode('=', $part);
+ if ($key === 't') {
+ $t_value = $value;
+ } elseif ($key === 's') {
+ $s_value = $value;
+ }
+ }
+
+ $to_hash = $t_value . '.' . $notificationData;
+ $hmac_signature = hash_hmac('sha256', $to_hash, $secret, true);
+ $hmac_base64 = base64_encode($hmac_signature);
+
+ return hash_equals($hmac_base64, $s_value);
+ }
+
+
+ public function validateKhipuCallback(Order $order, $notificationData, $apiVersion)
+ {
+ if (!$order || !$order->getIncrementId()) {
+ throw new \Exception('Order #' . $_REQUEST['order_id'] . ' does not exist');
+ }
+
+ if ($apiVersion != '3.0') {
+ throw new \Exception('Invalid notification API version.');
+ }
+
+ if ($notificationData['receiver_id'] != $this->scopeConfig->getValue('payment/simplified/merchant_id')) {
+ throw new \Exception('Invalid receiver ID');
+ }
+
+ if ($notificationData['custom'] != $order->getPayment()->getAdditionalInformation('khipu_order_token')) {
+ throw new \Exception('Invalid transaction ID');
+ }
+
+ if ($notificationData['amount'] != number_format($order->getGrandTotal(),
+ $this->khipuPayment->getDecimalPlaces($order->getOrderCurrencyCode()), '.', '')
+ ) {
+ throw new \Exception('Amount mismatch');
+ }
+
+ if ($notificationData['currency'] != $order->getOrderCurrencyCode()) {
+ throw new \Exception('Currency mismatch');
+ }
+
+ $responseTxt = 'Pago Khipu Aceptado
';
+ $responseTxt .= 'TransactionId: ' . $notificationData['transaction_id'] . '
';
+ $responseTxt .= 'PaymentId: ' . $notificationData['payment_id'] . '
';
+ $responseTxt .= 'Subject: ' . $notificationData['subject'] . '
';
+ $responseTxt .= 'Amount: ' . $notificationData['amount'] .' '.$notificationData['currency'] .'
';
+ $responseTxt .= 'Body: ' . $notificationData['body'] . '
';
+ $responseTxt .= 'Bank: ' . $notificationData['bank'] . '
';
+ $responseTxt .= 'Bank Account Number: ' . $notificationData['bank_account_number'] . '
';
+ $responseTxt .= 'Payer Name: ' . $notificationData['payer_name'] . '
';
+ $responseTxt .= 'Payer Email: ' . $notificationData['payer_email'] . '
';
+ $responseTxt .= 'Personal Identifier: ' . $notificationData['personal_identifier'] . '
';
+
+ $invoice = $order->prepareInvoice();
+ $invoice->register();
+ $invoice->save();
+
+ $paymentCompleteStatus = $this->scopeConfig->getValue('payment/simplified/payment_complete_status');
+
+ $order->setState($paymentCompleteStatus, false, "Pago Realizado con Khipu", true);
+ $order->setStatus($order->getConfig()->getStateDefaultStatus($paymentCompleteStatus));
+ $order->setIsCustomerNotified(true);
+ $order->addStatusToHistory($paymentCompleteStatus, $responseTxt);
+ $order->save();
+
+ $this->orderSender->send($order);
}
}
diff --git a/Model/Simplified.php b/Model/Simplified.php
index adaa62f..f1b0e4b 100755
--- a/Model/Simplified.php
+++ b/Model/Simplified.php
@@ -21,7 +21,6 @@
use Magento\Store\Model\StoreManagerInterface;
use Magento\Sales\Model\Order\Email\Sender\OrderSender;
-
class Simplified extends \Magento\Payment\Model\Method\AbstractMethod
{
const KHIPU_MAGENTO_VERSION = "2.4.10";
@@ -35,24 +34,6 @@ class Simplified extends \Magento\Payment\Model\Method\AbstractMethod
protected $_canUseCheckout = true;
protected $_canFetchTransactionInfo = true;
- /**
- * @param Context $context
- * @param Registry $registry
- * @param ExtensionAttributesFactory $extensionFactory
- * @param AttributeValueFactory $customAttributeFactory
- * @param Data $paymentData
- * @param ScopeConfigInterface $scopeConfig
- * @param Logger $logger
- * @param UrlInterface $urlBuilder
- * @param StoreManagerInterface $storeManager
- * @param AbstractResource|null $resource
- * @param AbstractDb|null $resourceCollection
- * @param array $data
- * @internal param ModuleListInterface $moduleList
- * @internal param TimezoneInterface $localeDate
- * @internal param CountryFactory $countryFactory
- * @internal param Http $response
- */
public function __construct(
Context $context,
Registry $registry,
@@ -85,16 +66,10 @@ public function __construct(
$this->urlBuilder = $urlBuilder;
$this->storeManager = $storeManager;
$this->orderSender = $orderSender;
-
}
- /**
- * @param Order $order
- * @return array
- */
public function getKhipuRequest(Order $order)
{
-
$token = substr(md5(rand()), 0, 32);
$payment = $order->getPayment();
@@ -106,58 +81,60 @@ public function getKhipuRequest(Order $order)
$description[] = number_format($item->getQtyOrdered(), 0) . ' × ' . $item->getName();
}
- $configuration = new \Khipu\Configuration();
- $configuration->setSecret($this->getConfigData('merchant_secret'));
- $configuration->setReceiverId($this->getConfigData('merchant_id'));
- $configuration->setPlatform('magento2-khipu', Simplified::KHIPU_MAGENTO_VERSION);
-
- $client = new \Khipu\ApiClient($configuration);
- $payments = new \Khipu\Client\PaymentsApi($client);
-
- error_log($this->getConfigData('merchant_secret'));
-
- error_log($this->getConfigData('merchant_id'));
-
- try {
-
- $opts = array(
- "transaction_id" => $order->getIncrementId(),
- "body" => join(', ',$description),
- "custom" => $payment->getAdditionalInformation('khipu_order_token'),
- "return_url" => $this->urlBuilder->getUrl('checkout/onepage/success'),
- "cancel_url" => $this->urlBuilder->getUrl('checkout/onepage/failure'),
- "notify_url" => ($this->urlBuilder->getUrl('khipupayment/payment/callback', array("order_id" => $order->getIncrementId()))),
- "notify_api_version" => "1.3",
- "payer_email" => $order->getCustomerEmail()
- );
-
- $createPaymentResponse = $payments->paymentsPost(
- $this->storeManager->getWebsite()->getName() . ' Carro #' . $order->getIncrementId()
- , $order->getOrderCurrencyCode()
- , number_format($order->getGrandTotal(), $this->getDecimalPlaces($order->getOrderCurrencyCode()), '.', '')
- , $opts
- );
- } catch (\Khipu\ApiException $e) {
- $error = $e->getResponseObject();
- $msg = "Error de comunicación con khipu.\n";
- $msg .= "Código: " . $error->getStatus() . "\n";
- $msg .= "Mensaje: " . $error->getMessage() . "\n";
- if (method_exists($error, 'getErrors')) {
- $msg .= "Errores:";
- foreach ($error->getErrors() as $errorItem) {
- $msg .= "\n" . $errorItem->getField() . ": " . $errorItem->getMessage();
- }
- }
- return array(
- 'reason' => $msg,
- 'status' => false
- );
+ $apiKey = $this->getConfigData('api_key');
+ $notifyUrl = $this->urlBuilder->getUrl('khipupayment/payment/callback', array("order_id" => $order->getIncrementId()));
+ $payerEmail = $order->getCustomerEmail();
+
+ $paymentData = [
+ 'amount' => (float)number_format($order->getGrandTotal(), $this->getDecimalPlaces($order->getOrderCurrencyCode()), '.', ''),
+ 'currency' => $order->getOrderCurrencyCode(),
+ 'subject' => $this->storeManager->getWebsite()->getName() . ' Carro #' . $order->getIncrementId(),
+ 'transaction_id' => $order->getIncrementId(),
+ 'body' => join(', ', $description),
+ 'custom' => $payment->getAdditionalInformation('khipu_order_token'),
+ 'return_url' => $this->urlBuilder->getUrl('checkout/onepage/success'),
+ 'cancel_url' => $this->urlBuilder->getUrl('checkout/onepage/failure'),
+ 'notify_url' => $notifyUrl,
+ 'notify_api_version' => '3.0',
+ 'payer_email' => $payerEmail
+ ];
+
+ $ch = curl_init('https://payment-api.khipu.com/v3/payments');
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+ curl_setopt($ch, CURLOPT_HTTPHEADER, [
+ 'Content-Type: application/json',
+ 'x-api-key: ' . $apiKey,
+ ]);
+ curl_setopt($ch, CURLOPT_POST, true);
+ curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($paymentData));
+ curl_setopt($ch, CURLOPT_TIMEOUT, 30); // Timeout in seconds
+ curl_setopt($ch, CURLOPT_FAILONERROR, true); // Fail on HTTP error
+ curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // Disable SSL peer verification
+ curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); // Disable SSL host verification
+
+ $response = curl_exec($ch);
+ $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
+ $curlError = curl_error($ch);
+ curl_close($ch);
+
+ if ($curlError) {
+ $msg = "Error de comunicación con Khipu: " . $curlError;
+ return ['reason' => $msg, 'status' => false];
}
- return array(
- 'status' => true,
- 'payment_url' => $createPaymentResponse->getSimplifiedTransferUrl()
- );
+ $responseData = json_decode($response, true);
+ if (isset($responseData['payment_id'])) {
+ $order->setKhipuPaymentId($responseData['payment_id']);
+ $order->save();
+ return ['status' => true, 'payment_url' => $responseData['simplified_transfer_url']];
+ } else {
+ $msg = "Error de comunicación con Khipu.\n";
+ if (isset($responseData['message'])) {
+ $msg .= "Mensaje: " . $responseData['message'] . "\n";
+ }
+
+ return ['reason' => $msg, 'status' => false];
+ }
}
public function getDecimalPlaces($currencyCode)
@@ -167,82 +144,4 @@ public function getDecimalPlaces($currencyCode)
}
return 2;
}
-
- /**
- * @param Order $order
- */
- public function validateKhipuCallback(Order $order, $notificationToken, $apiVersion)
- {
- if (!$order || !$order->getIncrementId()) {
- throw new \Exception('Order #' . $_REQUEST['order_id'] . ' does not exists');
- }
-
- $payment = $order->getPayment();
-
- if ($apiVersion != '1.3') {
- throw new \Exception('Invalid notification api version.');
- }
- $configuration = new \Khipu\Configuration();
- $configuration->setSecret($this->getConfigData('merchant_secret'));
- $configuration->setReceiverId($this->getConfigData('merchant_id'));
- $configuration->setPlatform('magento2-khipu', Simplified::KHIPU_MAGENTO_VERSION);
-
- $client = new \Khipu\ApiClient($configuration);
- $payments = new \Khipu\Client\PaymentsApi($client);
-
- try {
- $paymentResponse = $payments->paymentsGet($notificationToken);
- } catch (\Khipu\ApiException $exception) {
- throw new \Exception(print_r($exception->getResponseObject(), TRUE));
- }
-
- if ($paymentResponse->getReceiverId() != $this->getConfigData('merchant_id')) {
- throw new \Exception('Invalid receiver id');
- }
-
- if ($paymentResponse->getCustom() != $payment->getAdditionalInformation('khipu_order_token')) {
- throw new \Exception('Invalid transaction id');
- }
-
- if ($paymentResponse->getStatus() != 'done') {
- throw new \Exception('Payment not done');
- }
-
- if ($paymentResponse->getAmount() != number_format($order->getGrandTotal(),
- $this->getDecimalPlaces($order->getOrderCurrencyCode()), '.', '')
- ) {
- throw new \Exception('Amount mismatch');
- }
-
- if ($paymentResponse->getCurrency() != $order->getOrderCurrencyCode()) {
- throw new \Exception('Currency mismatch');
- }
-
- $responseTxt = 'Pago Khipu Aceptado
';
- $responseTxt .= 'TransactionId: ' . $paymentResponse->getTransactionId() . '
';
- $responseTxt .= 'PaymentId: ' . $paymentResponse->getPaymentId() . '
';
- $responseTxt .= 'Subject: ' . $paymentResponse->getSubject() . '
';
- $responseTxt .= 'Amount: ' . $paymentResponse->getAmount() .' '.$paymentResponse->getCurrency() .'
';
- $responseTxt .= 'Status: ' . $paymentResponse->getStatus() .' - ' . $paymentResponse->getStatusDetail() .'
';
- $responseTxt .= 'Body: ' . $paymentResponse->getBody() . '
';
- $responseTxt .= 'Bank: ' . $paymentResponse->getBank() . '
';
- $responseTxt .= 'Bank Account Number: ' . $paymentResponse->getBankAccountNumber() . '
';
- $responseTxt .= 'Payer Name: ' . $paymentResponse->getPayerName() . '
';
- $responseTxt .= 'Payer Email: ' . $paymentResponse->getPayerEmail() . '
';
- $responseTxt .= 'Personal Identifier: ' . $paymentResponse->getPersonalIdentifier() . '
';
-
- $invoice = $order->prepareInvoice();
- $invoice->register();
- $invoice->save();
-
- $paymentCompleteStatus = $this->getConfigData('payment_complete_status');
-
- $order->setState($paymentCompleteStatus, false, "Pago Realizado con Khipu", true);
- $order->setStatus($order->getConfig()->getStateDefaultStatus($paymentCompleteStatus));
- $order->setIsCustomerNotified(true);
- $order->addStatusToHistory($paymentCompleteStatus, $responseTxt);
- $order->save();
-
- $this->orderSender->send($order);
- }
}
diff --git a/README.md b/README.md
index a1b5aec..17381fc 100755
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
# Magento 2 Khipu Plugin
-khipu payment gateway Magento 2.4.10 plugin.
+khipu payment gateway Magento 2.5 plugin.
This version is compatible with Magento 2.3 to 2.6
@@ -8,7 +8,7 @@ You can sign up for khipu account at
## Install via Composer
-You can install Magento 2.4.10 khipu plugin via [Composer](http://getcomposer.org/). Run the following command in your terminal:
+You can install Magento 2.5 khipu plugin via [Composer](http://getcomposer.org/). Run the following command in your terminal:
1. Go to your Magento 2 root folder.
diff --git a/composer.json b/composer.json
index 4f00174..c3ff47b 100755
--- a/composer.json
+++ b/composer.json
@@ -2,14 +2,11 @@
"name": "khipu/magento2-khipu",
"type": "magento2-module",
"description": "khipu integration for Magento 2",
- "version": "2.4.10",
+ "version": "2.5",
"homepage": "https://khipu.com",
"license": [
"OSL-3.0"
],
- "require": {
- "khipu/khipu-api-client": "3.0.0.x-dev"
- },
"autoload": {
"files": [ "registration.php" ],
"psr-4": {
diff --git a/etc/adminhtml/system.xml b/etc/adminhtml/system.xml
index 39d66f4..1f90ac4 100755
--- a/etc/adminhtml/system.xml
+++ b/etc/adminhtml/system.xml
@@ -15,10 +15,14 @@
-
+
+
+
+
-
+
+
@@ -35,6 +39,4 @@
-
-
-
+
\ No newline at end of file
diff --git a/etc/di.xml b/etc/di.xml
index 2974214..b6d67b5 100644
--- a/etc/di.xml
+++ b/etc/di.xml
@@ -8,4 +8,9 @@
Magento\Sales\Model\Order\Email\Sender\OrderSender
+
+
+ Magento\Sales\Model\Order\Email\Sender\OrderSender
+
+
\ No newline at end of file
diff --git a/etc/module.xml b/etc/module.xml
index 1475be1..9e4e3a5 100755
--- a/etc/module.xml
+++ b/etc/module.xml
@@ -1,6 +1,6 @@
-
+