-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
olxndr
committed
Aug 9, 2024
0 parents
commit 84444c2
Showing
13 changed files
with
1,155 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
.idea |
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
# prestashop-8-shkeeper-payment-module | ||
SHKeeper payment gateway plugin for PrestaShop | ||
|
||
*Module has been tested on CMS Prestashop 8.1.7* | ||
|
||
## Installation | ||
### Upload via Module Manager | ||
|
||
Download from [Github releases page](https://github.com/vsys-host/prestashop-8-shkeeper-payment-module/releases) the latest module archive `prestashop-8-shkeeper-payment-module.zip` | ||
* Upload `prestashop-8-shkeeper-payment-module.zip` to your PrestaShop installation using the administrator menu _Modules_ -> _Module Manager_ -> _Upload a module_ | ||
* Configure the module (_Configure_) | ||
|
||
### Manual Module Installation | ||
|
||
In rare cases, you may need to install a module by manually transferring the files onto the server. This is recommended only when absolutely necessary, for example when your server is not configured to allow automatic installations. | ||
|
||
This procedure requires you to be familiar with the process of transferring files using an SFTP client. It is recommended for advanced users and developers. | ||
|
||
Detailed instruction can be found on official PrestaShop [site](https://addons.prestashop.com/en/content/13-installing-modules) | ||
## Configuration | ||
|
||
After successful installation you should configure module. At the payment module configuration page: | ||
1. Enter the api key, api url, instructions for your customers, and that all. | ||
* Instruction – Contains the explanation on how to pay by SHKeeper. | ||
* Api key - Authorization and identification SHKeeper key. You can generate it in SHKeeper admin panel for any crypto wallet. | ||
* Api url - SHKeeper server api entry point. | ||
2. Once done save the changes. | ||
|
||
## You are done! | ||
|
||
## Testing | ||
|
||
You can use our demo SHKeeper installation to test module with your PrestaShop. SHKeeper demo version working in a Testnet network, do not use it for real payments. | ||
SHKeeper demo version is available from us, so you can try it yourself without installing it: | ||
|
||
[SHKeeper demo](https://demo.shkeeper.io/) | ||
|
||
**Login:** admin | ||
|
||
**Password:** admin |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
<?xml version="1.0" encoding="UTF-8" ?> | ||
<module> | ||
<name>shkeeper</name> | ||
<displayName><![CDATA[SHKeeper]]></displayName> | ||
<version><![CDATA[1.0.0]]></version> | ||
<discription>SHKeeper Cryptocurrencies Payment Gateway</discription> | ||
<author><![CDATA[vsys-host]]></author> | ||
<tab><![CDATA[payments_gateways]]></tab> | ||
<need_instance>0</need_instance> | ||
<is_configrable>1</is_configrable> | ||
</module> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,135 @@ | ||
<?php | ||
|
||
class ShkeeperCallbackModuleFrontController extends ModuleFrontController | ||
{ | ||
public function postProcess() | ||
{ | ||
|
||
// collect data stream | ||
$data = file_get_contents('php://input'); | ||
$headers = getallheaders(); | ||
|
||
$message = null; | ||
|
||
// validate if the request singned by SHKeeper API | ||
if (! $this->isSignedRequest($headers)) { | ||
$message = 'Unauthorized Request!...'; | ||
$this->response($message, 401); | ||
} | ||
|
||
$data_collected = json_decode($data, true); | ||
|
||
if (json_last_error() !== JSON_ERROR_NONE ) { | ||
$message = 'JSON: ' . json_last_error_msg(); | ||
$this->response($message); | ||
} | ||
|
||
$externalId = (int) $data_collected['external_id']; | ||
|
||
// fetch order ID by external ID | ||
$orderId = Order::getIdByCartId($externalId); | ||
|
||
// terminate on Order Not Found | ||
if (! $orderId) { | ||
$transactionDate = $data_collected['transactions'][0]['date']; | ||
|
||
// Stop receive confirmation for missing orders | ||
if ($this->getInterval($transactionDate)) { | ||
$message = 'Please Contact Store Administration'; | ||
$this->response($message, 202); | ||
} | ||
|
||
$message = 'Wrong Credentials!...'; | ||
$this->response($message, 404); | ||
} | ||
|
||
$order = new Order($orderId); | ||
|
||
// collect new transactions and save data on order update | ||
foreach ($data_collected['transactions'] as $transaction) { | ||
if ($transaction['trigger']) { | ||
|
||
$orderPayment = new OrderPayment(); | ||
$orderPayment->order_reference = $orderId; | ||
$orderPayment->id_currency = $order->id_currency; | ||
$orderPayment->amount = (float)$transaction['amount_fiat']; | ||
$orderPayment->payment_method = $this->module->name . ' ' . $transaction['crypto']; | ||
$orderPayment->transaction_id = $transaction['txid']; | ||
$orderPayment->date_add = date('Y-m-d H:i:s'); | ||
|
||
// Save the payment object | ||
if ($orderPayment->save()) { | ||
// Associate the payment with the order | ||
$order->addOrderPayment($orderPayment->amount, $orderPayment->payment_method, $orderPayment->transaction_id); | ||
} | ||
} | ||
} | ||
|
||
// when partial payment update order status with "PS_OS_SHKEEPER_PARTIAL_PAYMENT" | ||
if (!$data_collected['paid']) { | ||
$newOrderStatus = Configuration::get('PS_OS_PAYMENT'); | ||
if (Configuration::get('PS_OS_SHKEEPER_PARTIAL_PAYMENT')) { | ||
$newOrderStatus = Configuration::get('PS_OS_SHKEEPER_PARTIAL_PAYMENT'); | ||
} | ||
$order->setCurrentState($newOrderStatus); | ||
$order->save(); | ||
} | ||
|
||
// when complete payment update order status with "PS_OS_SHKEEPER_ACCEPTED" | ||
if ($data_collected['paid']) { | ||
$newOrderStatus = Configuration::get('PS_OS_PAYMENT'); | ||
if (Configuration::get('PS_OS_SHKEEPER_ACCEPTED')) { | ||
$newOrderStatus = Configuration::get('PS_OS_SHKEEPER_ACCEPTED'); | ||
} | ||
$order->setCurrentState($newOrderStatus); | ||
$order->save(); | ||
} | ||
|
||
$this->response('Order status updated.', 202); | ||
|
||
} | ||
|
||
private function response(string $message, $responseCode = 200): void | ||
{ | ||
header("Content-Type: application/json"); | ||
http_response_code($responseCode); | ||
echo $message; | ||
exit; | ||
} | ||
|
||
private function isSignedRequest(array $header = []) | ||
{ | ||
|
||
// terminate on empty headers | ||
if (empty($header)) { | ||
return false; | ||
} | ||
|
||
// terminate on SHKeeper NOT SET | ||
if (empty($header['X-Shkeeper-Api-Key'])) { | ||
return false; | ||
} | ||
|
||
// fetch saved api | ||
$shkeeperKey = Configuration::get('SHKEEPER_APIKEY'); | ||
|
||
// terminate on missy requests | ||
if ($shkeeperKey != $header['X-Shkeeper-Api-Key']) { | ||
return false; | ||
} | ||
|
||
return true; | ||
} | ||
|
||
/** | ||
* Calculate the Date interval | ||
* @param string $date | ||
* @return bool | ||
*/ | ||
private function getInterval(string $date): bool | ||
{ | ||
$paymentDate = new DateTimeImmutable($date); | ||
$today = new DateTimeImmutable(); | ||
return (bool) $paymentDate->diff($today)->format('%a'); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
<?php | ||
|
||
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); | ||
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT'); | ||
|
||
header('Cache-Control: no-store, no-cache, must-revalidate'); | ||
header('Cache-Control: post-check=0, pre-check=0', false); | ||
header('Pragma: no-cache'); | ||
|
||
header('Location: ../'); | ||
exit; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
<?php | ||
class ShkeeperValidationModuleFrontController extends ModuleFrontController | ||
{ | ||
public function postProcess() | ||
{ | ||
$cart = $this->context->cart; | ||
|
||
if ( | ||
$cart->id_customer == 0 || | ||
$cart->id_address_delivery == 0 || | ||
$cart->id_address_invoice == 0 || | ||
!$this->module->active | ||
) { | ||
Tools::redirect("index.php?controller=order&step=1"); | ||
|
||
return; | ||
} | ||
|
||
// Check that this payment option is still available in case the customer changed his address just before the end of the checkout process | ||
$authorized = false; | ||
foreach (Module::getPaymentModules() as $module) { | ||
if ($module["name"] == "shkeeper") { | ||
$authorized = true; | ||
break; | ||
} | ||
} | ||
|
||
if (!$authorized) { | ||
exit( | ||
$this->trans( | ||
"This payment method is not available.", | ||
[], | ||
"Modules.Shkeeper.Shop" | ||
) | ||
); | ||
} | ||
|
||
$customer = new Customer($cart->id_customer); | ||
|
||
if (!Validate::isLoadedObject($customer)) { | ||
Tools::redirect("index.php?controller=order&step=1"); | ||
|
||
return; | ||
} | ||
|
||
// save address with amount required for this order | ||
|
||
$walletAddress = $this->context->cookie->__get("shkeeper_wallet"); | ||
$amount = $this->context->cookie->__get("shkeeper_amount"); | ||
|
||
$currency = $this->context->currency; | ||
$total = (float) $cart->getOrderTotal(true, Cart::BOTH); | ||
|
||
$this->module->validateOrder( | ||
$cart->id, | ||
(int) Configuration::get("PS_OS_SHKEEPER_PENDING"), | ||
0, | ||
$this->module->displayName, | ||
null, | ||
[], | ||
(int) $currency->id, | ||
false, | ||
$customer->secure_key | ||
); | ||
|
||
// OrderId | ||
$orderId = $this->module->currentOrder; | ||
|
||
// messages | ||
$message = "Wallet: " . $this->context->cookie->__get("shkeeper_wallet") . " - "; | ||
$message .= "Amount: " . $this->context->cookie->__get("shkeeper_amount") . " "; | ||
$message .= $this->context->cookie->__get("shkeeper_crypto"); | ||
|
||
// save address and amout to order messages | ||
$this->addOrderMessage($orderId, $message, $cart->id_customer); | ||
|
||
Tools::redirect( | ||
$this->context->link->getPageLink( | ||
"order-confirmation", | ||
true, | ||
(int) $this->context->language->id, | ||
[ | ||
"id_cart" => (int) $cart->id, | ||
"id_module" => (int) $this->module->id, | ||
"id_order" => (int) $this->module->currentOrder, | ||
"key" => $customer->secure_key, | ||
] | ||
) | ||
); | ||
} | ||
|
||
private function addOrderMessage($orderId, $message, $cutomerId) | ||
{ | ||
if (version_compare(_PS_VERSION_, "1.7.0", ">")) { | ||
// Add this message in the customer thread | ||
$customer_thread = new CustomerThread(); | ||
$customer_thread->id_contact = 0; | ||
$customer_thread->id_customer = (int) $cutomerId; | ||
$customer_thread->id_shop = (int) $this->context->shop->id; | ||
$customer_thread->id_order = (int) $orderId; | ||
$customer_thread->id_lang = (int) $this->context->language->id; | ||
$customer_thread->token = Tools::passwdGen(12); | ||
$customer_thread->add(); | ||
|
||
$customer_message = new CustomerMessage(); | ||
$customer_message->id_customer_thread = $customer_thread->id; | ||
$customer_message->id_employee = 0; | ||
$customer_message->message = $message; | ||
$customer_message->private = 1; | ||
$customer_message->add(); | ||
} else { | ||
$orderMessage = new Message(); | ||
$orderMessage->id_order = $orderId; | ||
$orderMessage->message = $message; | ||
$orderMessage->private = true; | ||
$orderMessage->save(); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
<?php | ||
|
||
class ShkeeperWalletModuleFrontController extends ModuleFrontController | ||
{ | ||
|
||
public function postProcess() | ||
{ | ||
$cryptoCurrency = Tools::getValue('currency'); | ||
|
||
if (empty($cryptoCurrency)) { | ||
return false; | ||
} | ||
|
||
$cart = $this->context->cart; | ||
$currency = $this->context->currency; | ||
|
||
$order_data = [ | ||
"external_id" => $cart->id, | ||
"fiat" => $currency->iso_code, | ||
"amount" => $cart->getOrderTotal(true, Cart::BOTH), | ||
"callback_url" => $this->context->link->getModuleLink('shkeeper', 'callback', ['ajax' => true]), | ||
]; | ||
|
||
$walletAddress = $this->postData("/$cryptoCurrency/payment_request", $order_data); | ||
$info = json_decode($walletAddress, true); | ||
$this->context->cookie->__set('shkeeper_wallet', $info['wallet']); | ||
$this->context->cookie->__set('shkeeper_amount', $info['amount']); | ||
$this->context->cookie->__set('shkeeper_crypto', $info['display_name']); | ||
|
||
header("Content-Type: application/json"); | ||
echo $walletAddress; | ||
exit; | ||
} | ||
|
||
private function postData(string $url, array $data = []) | ||
{ | ||
$headers = [ | ||
"X-Shkeeper-Api-Key: " . Configuration::get('SHKEEPER_APIKEY'), | ||
]; | ||
|
||
$base_url = rtrim(Configuration::get('SHKEEPER_APIURL'), '/'); | ||
|
||
$options = [ | ||
CURLOPT_URL => $base_url . $url, | ||
CURLOPT_RETURNTRANSFER => true, | ||
CURLOPT_HTTPHEADER => $headers, | ||
CURLOPT_POSTFIELDS => json_encode($data), | ||
CURLOPT_POST => true, | ||
]; | ||
|
||
$curl = curl_init(); | ||
curl_setopt_array($curl, $options); | ||
$response = curl_exec($curl); | ||
curl_close($curl); | ||
|
||
return $response; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
<?php | ||
|
||
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); | ||
header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT'); | ||
|
||
header('Cache-Control: no-store, no-cache, must-revalidate'); | ||
header('Cache-Control: post-check=0, pre-check=0', false); | ||
header('Pragma: no-cache'); | ||
|
||
header('Location: ../'); | ||
exit; |
Oops, something went wrong.