281 lines
11 KiB
PHP
281 lines
11 KiB
PHP
<?php
|
|
namespace Opencart\Admin\Controller\Extension\Btcpay\Payment;
|
|
|
|
use BTCPayServer\Client\Store;
|
|
use BTCPayServer\Client\Webhook;
|
|
|
|
require_once DIR_EXTENSION . 'btcpay/system/library/btcpay/autoload.php';
|
|
require_once DIR_EXTENSION . 'btcpay/system/library/btcpay/version.php';
|
|
|
|
class Btcpay extends \Opencart\System\Engine\Controller {
|
|
private $error = [];
|
|
|
|
public function index(): void {
|
|
$this->load->language('extension/btcpay/payment/btcpay');
|
|
$this->document->setTitle($this->language->get('heading_title'));
|
|
|
|
$this->load->model('setting/setting');
|
|
$this->load->model('localisation/order_status');
|
|
$this->load->model('localisation/geo_zone');
|
|
|
|
$data['save'] = $this->url->link('extension/btcpay/payment/btcpay|save', 'user_token=' . $this->session->data['user_token']);
|
|
$data['back'] = $this->url->link('marketplace/extension', 'user_token=' . $this->session->data['user_token'] . '&type=payment');
|
|
$data['cancel'] = $this->url->link('marketplace/extension', 'user_token=' . $this->session->data['user_token'] . '&type=payment', true);
|
|
$data['order_statuses'] = $this->model_localisation_order_status->getOrderStatuses();
|
|
|
|
$data['geo_zones'] = $this->model_localisation_geo_zone->getGeoZones();
|
|
|
|
if (isset($this->error['warning'])) {
|
|
$data['error_warning'] = $this->error['warning'];
|
|
} else {
|
|
$data['error_warning'] = '';
|
|
}
|
|
|
|
if (isset($this->session->data['success'])) {
|
|
$data['success'] = $this->session->data['success'];
|
|
unset($this->session->data['success']);
|
|
} else {
|
|
$data['success'] = '';
|
|
}
|
|
|
|
$data['breadcrumbs'] = [];
|
|
$data['breadcrumbs'][] = array(
|
|
'text' => $this->language->get('text_home'),
|
|
'href' => $this->url->link('common/dashboard', 'user_token=' . $this->session->data['user_token'], true)
|
|
);
|
|
$data['breadcrumbs'][] = array(
|
|
'text' => $this->language->get('text_extension'),
|
|
'href' => $this->url->link('marketplace/extension', 'user_token=' . $this->session->data['user_token'] . '&type=payment', true)
|
|
);
|
|
$data['breadcrumbs'][] = array(
|
|
'text' => $this->language->get('heading_title'),
|
|
'href' => $this->url->link('extension/btcpay/payment/btcpay', 'user_token=' . $this->session->data['user_token'], true)
|
|
);
|
|
|
|
$fields = [
|
|
'payment_btcpay_status',
|
|
'payment_btcpay_url',
|
|
'payment_btcpay_api_auth_token',
|
|
'payment_btcpay_btcpay_storeid',
|
|
'payment_btcpay_webhook',
|
|
'payment_btcpay_webhook_delete',
|
|
'payment_btcpay_modal_mode',
|
|
'payment_btcpay_new_status_id',
|
|
'payment_btcpay_paid_status_id',
|
|
'payment_btcpay_settled_status_id',
|
|
'payment_btcpay_settled_paidover_status_id',
|
|
'payment_btcpay_invalid_status_id',
|
|
'payment_btcpay_expired_status_id',
|
|
'payment_btcpay_expired_partialpayment_status_id',
|
|
'payment_btcpay_expired_paidlate_status_id',
|
|
'payment_btcpay_refunded_status_id',
|
|
'payment_btcpay_total',
|
|
'payment_btcpay_geo_zone_id',
|
|
'payment_btcpay_debug_mode',
|
|
];
|
|
|
|
// Process our fields to be sure they are displayed.
|
|
foreach ($fields as $field) {
|
|
if (isset($this->request->post[$field])) {
|
|
$data[$field] = $this->request->post[$field];
|
|
} else {
|
|
$data[$field] = $this->config->get($field);
|
|
}
|
|
}
|
|
|
|
$data['payment_btcpay_sort_order'] = isset($this->request->post['payment_btcpay_sort_order']) ?
|
|
$this->request->post['payment_btcpay_sort_order'] : $this->config->get('payment_btcpay_sort_order');
|
|
|
|
$data['header'] = $this->load->controller('common/header');
|
|
$data['column_left'] = $this->load->controller('common/column_left');
|
|
$data['footer'] = $this->load->controller('common/footer');
|
|
|
|
$this->response->setOutput($this->load->view('extension/btcpay/payment/btcpay', $data));
|
|
}
|
|
|
|
protected function validate($messages): array {
|
|
|
|
$this->load->language('extension/btcpay/payment/btcpay');
|
|
if (!$this->user->hasPermission('modify', 'extension/btcpay/payment/btcpay')) {
|
|
$messages['error'] = $this->language->get('error_permission');
|
|
}
|
|
|
|
if (!class_exists('BTCPayServer\Client\Health')) {
|
|
$messages['error'] = $this->language->get('error_composer');
|
|
}
|
|
|
|
if (!isset($messages['error'])) {
|
|
$host = $this->request->post['payment_btcpay_url'];
|
|
$apiKey = $this->request->post['payment_btcpay_api_auth_token'];
|
|
$storeId = $this->request->post['payment_btcpay_btcpay_storeid'];
|
|
|
|
try {
|
|
$client = new Store($host, $apiKey);
|
|
$store = $client->getStore($storeId);
|
|
if (empty($store->getId())) {
|
|
$messages['error'] = $this->language->get('error_store_not_found');
|
|
}
|
|
} catch (\Throwable $e) {
|
|
$messages['error'] = $this->language->get('error_connect_to_btcpay');
|
|
$this->log->write($e->getMessage());
|
|
}
|
|
}
|
|
|
|
return $messages;
|
|
}
|
|
|
|
public function save(): void {
|
|
$this->load->language('extension/btcpay/payment/btcpay');
|
|
$this->load->model('setting/setting');
|
|
|
|
$json = [];
|
|
$redirect = false;
|
|
|
|
$json = $this->validate($json);
|
|
|
|
if (empty($json['error'])) {
|
|
$host = $this->request->post['payment_btcpay_url'];
|
|
$apiKey = $this->request->post['payment_btcpay_api_auth_token'];
|
|
$storeId = $this->request->post['payment_btcpay_btcpay_storeid'];
|
|
|
|
// On saving we create a webhook if there is none yet.
|
|
if ($this->webhookExists() === false) {
|
|
if ($whData = $this->webhookSetup($host, $apiKey, $storeId)) {
|
|
$this->request->post['payment_btcpay_webhook'] = $whData;
|
|
$json['success'] = $this->language->get('notice_success_create_webhook');
|
|
$redirect = true;
|
|
} else {
|
|
$json['error'] = $this->language->get('error_creating_webhook');
|
|
}
|
|
} else {
|
|
// Check if the user wants to delete an existing webhook.
|
|
if (isset($this->request->post['payment_btcpay_webhook_delete']) &&
|
|
$this->request->post['payment_btcpay_webhook_delete'] === '1'
|
|
) {
|
|
// Try to delete the webhook on the provided host.
|
|
$this->webhookDelete($host, $apiKey, $storeId);
|
|
unset($this->request->post['payment_btcpay_webhook']);
|
|
unset($this->request->post['payment_btcpay_webhook_delete']);
|
|
$json['success'] = $this->language->get('notice_success_delete_webhook');
|
|
$redirect = true;
|
|
} else {
|
|
// Need to convert existing webhook values back to array for storage.
|
|
if (isset($this->request->post['payment_btcpay_webhook'])) {
|
|
$whString = $this->request->post['payment_btcpay_webhook'];
|
|
$whString = str_replace(['ID: ', 'SECRET: ', 'URL: '], '', $whString);
|
|
$whArr = explode(' | ', $whString);
|
|
if (count($whArr) === 3) {
|
|
$whData = [
|
|
'id' => $whArr[0],
|
|
'secret' => $whArr[1],
|
|
'url' => $whArr[2]
|
|
];
|
|
$this->request->post['payment_btcpay_webhook'] = $whData;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (empty($json['error'])) {
|
|
if (!empty($json['success'])) {
|
|
$json['success'] = $this->language->get('notice_success') . ' ' . $json['success'];
|
|
} else {
|
|
$json['success'] = $this->language->get('notice_success');
|
|
}
|
|
$this->model_setting_setting->editSetting('payment_btcpay', $this->request->post);
|
|
}
|
|
|
|
if ($redirect) {
|
|
$this->session->data['success'] = $json['success'];
|
|
unset($json['success']);
|
|
$json['redirect'] = $this->url->link('extension/btcpay/payment/btcpay', 'user_token=' . $this->session->data['user_token'], true);
|
|
}
|
|
|
|
$this->response->addHeader('Content-Type: application/json');
|
|
$this->response->setOutput(json_encode($json));
|
|
}
|
|
|
|
public function install(): void {
|
|
$this->load->model('extension/btcpay/payment/btcpay');
|
|
$this->model_extension_btcpay_payment_btcpay->install();
|
|
}
|
|
|
|
public function uninstall(): void {
|
|
$this->load->model('extension/btcpay/payment/btcpay');
|
|
$this->model_extension_btcpay_payment_btcpay->uninstall();
|
|
}
|
|
|
|
private function webhookExists(): bool {
|
|
// Check if the config is any value set at all.
|
|
$data = $this->config->get('payment_btcpay_webhook');
|
|
if (empty($data) || !is_array($data)) {
|
|
return false;
|
|
}
|
|
|
|
// todo: load webhook form BTCPay to check if the callback url domain is the same
|
|
|
|
return true;
|
|
}
|
|
|
|
private function webhookSetup($host, $apiKey, $storeId): ?array {
|
|
$whEvents = [
|
|
'InvoiceReceivedPayment',
|
|
'InvoicePaymentSettled',
|
|
'InvoiceProcessing',
|
|
'InvoiceExpired',
|
|
'InvoiceSettled',
|
|
'InvoiceInvalid'
|
|
];
|
|
|
|
try {
|
|
$whClient = new Webhook( $host, $apiKey );
|
|
$webhook = $whClient->createWebhook(
|
|
$storeId,
|
|
$this->webhookCallbackUrl(),
|
|
$whEvents,
|
|
null
|
|
);
|
|
|
|
// Prepare data for settings storage.
|
|
$whData = [
|
|
'id' => $webhook->getData()['id'],
|
|
'secret' => $webhook->getData()['secret'],
|
|
'url' => $webhook->getData()['url']
|
|
];
|
|
|
|
return $whData;
|
|
} catch (\Throwable $e) {
|
|
$this->log->write($e->getMessage());
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
private function webhookDelete($host, $apiKey, $storeId): void {
|
|
$data = $this->config->get('payment_btcpay_webhook');
|
|
|
|
$client = new \BTCPayServer\Client\Webhook($host, $apiKey);
|
|
try {
|
|
$client->deleteWebhook($storeId, $data['id']);
|
|
} catch (\Throwable $e) {
|
|
$this->log->write('Error deleting webhook: ' . $e->getMessage());
|
|
}
|
|
}
|
|
|
|
private function webhookCallbackUrl(): string {
|
|
$url = $this->url->link('extension/btcpay/payment/btcpay|callback', '', true);
|
|
|
|
// As we are in admin controller context we need to strip out the admin
|
|
// path to receive the correct frontend callback url.
|
|
$adminPathParts = explode('/', DIR_APPLICATION);
|
|
end($adminPathParts); // Last array item is empty.
|
|
$adminPath = prev($adminPathParts);
|
|
if (!empty($adminPath)) {
|
|
$url = str_replace($adminPath . '/', '', $url);
|
|
}
|
|
|
|
return $url;
|
|
}
|
|
}
|