aboutsummaryrefslogtreecommitdiff
path: root/plugin/src/GNU-taler-payment
diff options
context:
space:
mode:
Diffstat (limited to 'plugin/src/GNU-taler-payment')
-rw-r--r--plugin/src/GNU-taler-payment/class-wc-gnutaler-gateway.php890
-rw-r--r--plugin/src/GNU-taler-payment/functions/functions.php224
-rw-r--r--plugin/src/GNU-taler-payment/functions/functionsTest.php157
-rw-r--r--plugin/src/GNU-taler-payment/js/WalletDetection.js43
-rw-r--r--plugin/src/GNU-taler-payment/js/taler-wallet-lib.js270
-rw-r--r--plugin/src/GNU-taler-payment/readme.txt59
6 files changed, 1643 insertions, 0 deletions
diff --git a/plugin/src/GNU-taler-payment/class-wc-gnutaler-gateway.php b/plugin/src/GNU-taler-payment/class-wc-gnutaler-gateway.php
new file mode 100644
index 0000000..0d8100b
--- /dev/null
+++ b/plugin/src/GNU-taler-payment/class-wc-gnutaler-gateway.php
@@ -0,0 +1,890 @@
+<?php /** @noinspection PhpUndefinedFieldInspection */
+/**
+ * @package GNUTalerPayment
+ */
+/**
+ * Plugin Name: GNU Taler Payment for Woocommerce
+ * Plugin URI: https://github.com/Sakaeo/GNU-Taler-Plugin
+ * //Or Wordpress pluin URI
+ * Description: This plugin enables the payment via the GNU Taler payment system
+ * Version: 1.0
+ * Author: Hofmann Dominique & Strübin Jan
+ * Author URI:
+ *
+ * License: GNU General Public License v3.0
+ * License URI: http://www.gnu.org/licenses/gpl-3.0.html
+ * WC requires at least: 2.2
+ **/
+
+/*
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+
+require_once ABSPATH . 'wp-admin/includes/plugin.php';
+
+//Exit if accessed directly.
+if ( ! defined( 'ABSPATH' ) ) {
+ exit();
+}
+
+/*
+ * This action hook registers our PHP class as a WooCommerce payment gateway
+ */
+
+/**
+ * Adds the GNU Taler payment method to the other payment gateways.
+ *
+ * @param $gateways - Array of all the payment gateways.
+ * @return array
+ * @since 0.6.0
+ */
+
+
+function gnutaler_add_gateway_class( $gateways ) {
+ $gateways[] = 'WC_GNUTaler_Gateway';
+ return $gateways;
+}
+
+add_filter( 'woocommerce_payment_gateways', 'gnutaler_add_gateway_class' );
+
+/**
+ * The class itself, please note that it is inside plugins_loaded action hook
+ */
+
+add_action( 'plugins_loaded', 'gnutaler_init_gateway_class' );
+
+
+function gnutaler_init_gateway_class()
+{
+ //Check if WooCommerce is active, if not then deactivate and show error message
+ if ( ! in_array( 'woocommerce/woocommerce.php', apply_filters('active_plugins', get_option('active_plugins' ) ), true ) ) {
+ deactivate_plugins(plugin_basename(__FILE__));
+ wp_die("<strong>GNU Taler</strong> requires <strong>WooCommerce</strong> plugin to work normally. Please activate it or install it from <a href=\"http://wordpress.org/plugins/woocommerce/\" target=\"_blank\">here</a>.<br /><br />Back to the WordPress <a href='" . get_admin_url(null, 'plugins.php') . "'>Plugins page</a>.");
+ }
+
+ /**
+ * GNU Taler Payment Gateway class.
+ *
+ * Handles the payments from the Woocommerce Webshop and sends the transactions to the GNU Taler Backend and the GNU Taler Wallet.
+ *
+ * @since 0.6.0
+ */
+ class WC_GNUTaler_Gateway extends WC_Payment_Gateway
+ {
+ /**
+ * Class constructor
+ */
+ public function __construct()
+ {
+ $this->id = 'gnutaler'; // payment gateway plugin ID
+ $this->icon = ''; // URL of the icon that will be displayed on checkout page near the gateway name
+ $this->has_fields = false; // There is no need for custom checkout fields, therefore set false
+ $this->method_title = 'GNU Taler Gateway';
+ $this->method_description = 'This plugin enables the payment via the GNU Taler payment system'; // will be displayed on the options page
+
+ // gateways can support refunds, saved payment methods,
+ $this->supports = array(
+ 'products', 'refunds',
+ );
+ // Method with all the options fields
+ $this->init_form_fields();
+
+ // Load the settings.
+ $this->init_settings();
+ $this->title = $this->get_option( 'title' );
+ $this->description = $this->get_option( 'description' );
+ $this->enabled = $this->get_option( 'enabled' );
+ $this->GNU_Taler_Backend_URL = $this->get_option( 'GNU_Taler_Backend_URL' );
+ $this->GNU_Taler_Backend_API_Key = $this->get_option( 'GNU_Taler_Backend_API_Key' );
+ $this->Payment_url = $this->get_option( 'Payment_url' );
+ $this->Order_text = $this->get_option( 'Order_text' );
+ $this->merchant_information = $this->get_option( 'merchant_information' );
+ $this->merchant_name = $this->get_option( 'merchant_name' );
+
+ //Here we add the Javascript files to the webserver
+ add_action( 'woocommerce_before_checkout_form', static function () {
+ wp_enqueue_script( 'taler-wallet-lib', plugin_dir_url( __FILE__ ) . 'js/taler-wallet-lib.js' );
+ } );
+ add_action( 'woocommerce_before_checkout_form', static function () {
+ wp_enqueue_script( 'WalletDetection', plugin_dir_url( __FILE__ ) . 'js/WalletDetection.js' );
+ } );
+
+ add_action( 'woocommerce_api_'. strtolower( get_class($this) ), array( $this, 'callback_handler' ) );
+
+ // This action hook saves the settings
+ add_action( 'woocommerce_update_options_payment_gateways_' . $this->id, array( $this, 'process_admin_options' ) );
+ }
+
+ /**
+ * Plugin options
+ */
+ public function init_form_fields()
+ {
+ $this->form_fields = array(
+ 'enabled' => array(
+ 'title' => 'Enable/Disable',
+ 'label' => 'Enable GNU Taler Gateway',
+ 'type' => 'checkbox',
+ 'description' => '',
+ 'default' => 'no',
+ ),
+ 'title' => array(
+ 'title' => 'Title',
+ 'type' => 'text',
+ 'description' => 'What name should the payment method have when the costumer can choose how to pay .',
+ 'default' => 'GNU Taler',
+ 'desc_tip' => true,
+ ),
+ 'description' => array(
+ 'title' => 'Description',
+ 'type' => 'textarea',
+ 'description' => 'This controls the description which the customer sees during checkout.',
+ 'default' => 'Pay with the new Payment method GNU Taler.',
+ ),
+ 'GNU_Taler_Backend_URL' => array(
+ 'title' => 'GNU Taler Backend URL',
+ 'type' => 'text',
+ 'description' => 'Set the URL of the GNU Taler Backend.',
+ 'default' => 'https://backend.demo.taler.net',
+ ),
+ 'GNU_Taler_Backend_API_Key' => array(
+ 'title' => 'GNU Taler Backend API Key',
+ 'type' => 'text',
+ 'description' => 'Set the API-key for the Authorization with the GNU Taler Backend.',
+ 'default' => 'ApiKey sandbox',
+ ),
+ 'Payment_url' => array(
+ 'title' => 'GNU Taler Payment url',
+ 'type' => 'text',
+ 'description' => 'Set the URL for your GNU Taler Wallet where the Coins of the costumer will be send to.',
+ 'default' => '',
+ ),
+ 'Order_text' => array(
+ 'title' => 'Summarytext of the order',
+ 'type' => 'text',
+ 'description' => 'Set the text the customer should see as a summary when he confirms the payment.',
+ 'default' => 'Order',
+ ),
+ 'merchant_information' => array(
+ 'title' => 'Enable/Disable',
+ 'label' => 'Enable sending your merchant information to the GNU Taler Backend',
+ 'type' => 'checkbox',
+ 'description' => 'Do you want to send your merchant information to the GNU Taler Backend via the transaction',
+ 'default' => 'yes',
+ ),
+ 'merchant_name' => array(
+ 'title' => 'Name of the webshop',
+ 'type' => 'text',
+ 'description' => 'Set the name of the webshop that the customer will see during the payment transaction.',
+ 'default' => '',
+ ),
+ );
+ }
+
+ /**
+ * Callback is called, when the payment succeeds.
+ *
+ * Is called on successful payment process.
+ * User is then being forwarded to the order details page.
+ *
+ * @since 0.6.0
+ */
+
+ public function callback_handler(): void
+ {
+
+ if ( is_user_logged_in() )
+ {
+ $user_id = WC()->customer->get_id();
+ }
+ else
+ {
+ $user_id = 'Guest';
+ }
+
+ if ( isset( $_GET['order_id'] ) ) {
+
+ //Gets the order id from the fulfillment url
+ $order_id_backend = $_GET['order_id'];
+ $order_id_array = explode( '-', $order_id_backend );
+ $order_id_name = $order_id_array[0];
+ $order_id = $order_id_array[1];
+ $wc_order = wc_get_order( $order_id );
+
+ //Completes the order
+ $wc_order->payment_complete();
+
+ //Empties the shopping cart
+ WC()->cart->empty_cart();
+
+ $this->add_log_entry('transaction', 'Userid: ' . $user_id . ' - Orderid: ' . $order_id . ' - Payment succeeded and the user was forwarded to the order confirmed page' );
+
+ wp_redirect( get_home_url() . '/checkout/order-received/' . $order_id . '/?key=' . $order_id_name );
+ exit;
+ }
+ wp_redirect(get_home_url() . '/my-account/orders/');
+ exit;
+ }
+
+ /**
+ * Sends a request to a url via HTTP.
+ *
+ * Sends a request to a GNU Taler Backend over HTTP and returns the result.
+ * The request can be sent as POST, GET, PUT or another method.
+ *
+ * @param $method - POST, GET, PUT or another method.
+ * @param $backend_url - URL to the GNU Taler Backend.
+ * @param $body - The content of the request.
+ * @param $purpose - What return value is to be expected.
+ * @return array The return array will either have the successful return value or a detailed error message.
+ * @since 0.6.0
+ *
+ */
+ public function call_api( $method, $backend_url, $body, $purpose ): array
+ {
+ //create_url
+ $url = $this->create_api_url( $backend_url, $purpose, $body );
+
+ //Initialize curl request
+ $curl = $this->curl_init( $method, $body, $url );
+
+ // EXECUTE:
+ $result = curl_exec( $curl );
+
+ //HTTP Status Error handling
+ $message_array = $this->curl_error_handling( $curl, $result );
+ curl_close( $curl );
+ return $message_array;
+ }
+
+ /**
+ * Checks if the return http code is a success and if not what kind of error status it is.
+ *
+ * If the request was successful an array will be returned with the boolean value true, the http code and the result of the response.
+ * If the request failed an array will be returned with the boolean value false, the http code and a detailed error message.
+ *
+ * @param $curl - Created curl request for error handling.
+ * @param $result - The response from the backend, that will be returned if the request was successful
+ * @return array - Array with a boolean, a http code and a message will be returned
+ * @since 0.6.0
+ *
+ */
+ public function curl_error_handling( $curl, $result ): array
+ {
+ $http_code = curl_getinfo( $curl, CURLINFO_HTTP_CODE );
+ if ( curl_error( $curl ) ) {
+ $error_msg = curl_error( $curl );
+ }
+ curl_close( $curl );
+ if ( isset( $error_msg ) ) {
+ return array(
+ 'result' => false,
+ 'http_code' => $http_code,
+ 'message' => $error_msg,
+ );
+ }
+ if ( $http_code === 200 ) {
+ return array(
+ 'result' => true,
+ 'http_code' => $http_code,
+ 'message' => $result,
+ );
+ }
+ if ( preg_match( '(4[0-9]{2})', $http_code ) ) {
+ switch ($http_code) {
+ case 400:
+ return array(
+ 'result' => false,
+ 'http_code' => $http_code,
+ 'message' => 'request',
+ );
+ break;
+ case 401:
+ return array(
+ 'result' => false,
+ 'http_code' => $http_code,
+ 'message' => 'Unauthorized',
+ );
+ break;
+ case 403:
+ return array(
+ 'result' => false,
+ 'http_code' => $http_code,
+ 'message' => 'Forbidden',
+ );
+ break;
+ case 404:
+ return array(
+ 'result' => false,
+ 'http_code' => $http_code,
+ 'message' => 'Page Not Found',
+ );
+ break;
+ default:
+ return array(
+ 'result' => false,
+ 'http_code' => $http_code,
+ 'message' => '4xx Client Error',
+ );
+ break;
+ }
+ } elseif ( preg_match( '(5[0-9]{2})', $http_code ) ) {
+ switch ( $http_code ) {
+ case '500':
+ return array(
+ 'result' => false,
+ 'http_code' => $http_code,
+ 'message' => 'Internal Server Error',
+ );
+ break;
+ case '502':
+ return array(
+ 'result' => false,
+ 'http_code' => $http_code,
+ 'message' => 'Bad Gateway',
+ );
+ break;
+ case '503':
+ return array(
+ 'result' => false,
+ 'http_code' => $http_code,
+ 'message' => 'Service Unavailable',
+ );
+ break;
+ case '504':
+ return array(
+ 'result' => false,
+ 'http_code' => $http_code,
+ 'message' => 'Gateway Timeout',
+ );
+ break;
+ default:
+ return array(
+ 'result' => false,
+ 'http_code' => $http_code,
+ 'message' => '5xx Client Error',
+ );
+ break;
+ }
+ } else {
+ return array(
+ 'result' => false,
+ 'http_code' => $http_code,
+ 'message' => 'http status error',
+ );
+ }
+ }
+
+ /**
+ * Initialises the curl request and sets some necessary options depending on the method.
+ *
+ * Depending of the method chosen different options for the curl request will be set.
+ * Not depending on the method the settings for a return value, Authorization and Content-Type are being set.
+ *
+ * @param $method - POST, GET, PUT or another method.
+ * @param $body - Content of the request.
+ * @param $url - URL where the request will be send
+ * @return false|resource - Either the configured curl request will be returned or false if an error appears.
+ * @since 0.6.0
+ */
+ public function curl_init( $method, $body, $url )
+ {
+ $curl = curl_init();
+ $apikey = $this->get_option( 'GNU_Taler_Backend_API_Key' );
+
+ switch ( $method ) {
+ case 'POST':
+ curl_setopt( $curl, CURLOPT_POST, 1 );
+ if ( $body ) {
+ curl_setopt( $curl, CURLOPT_POSTFIELDS, $body );
+ }
+ break;
+ case 'PUT':
+ curl_setopt( $curl, CURLOPT_CUSTOMREQUEST, 'PUT' );
+ if ( $body ) {
+ curl_setopt( $curl, CURLOPT_POSTFIELDS, $body );
+ }
+ break;
+ case 'GET':
+ curl_setopt( $curl, CURLOPT_VERBOSE, 1 );
+ break;
+ default:
+ curl_setopt( $curl, CURLOPT_CUSTOMREQUEST, $method );
+ break;
+ }
+
+ // OPTIONS:
+ curl_setopt( $curl, CURLOPT_URL, $url );
+ curl_setopt( $curl, CURLOPT_HTTPHEADER, array(
+ 'Authorization: ' . $apikey,
+ 'Content-Type: application/json',
+ ) );
+ curl_setopt( $curl, CURLOPT_RETURNTRANSFER, 1 );
+ curl_setopt ($curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC );
+
+ return $curl;
+ }
+
+ /**
+ * Creates the final url depending on the purpose.
+ *
+ * @param $url - URL where the request will be send.
+ * @param $purpose - What will be added to the url.
+ * @param $body - Content of the request.
+ * @return string - return the final url.
+ * @since 0.6.0
+ */
+ public function create_api_url ($url, $purpose, $body ): string
+ {
+ if ( $purpose === 'create_order' ) {
+ return $url . '/order';
+ }
+ if ( $purpose === 'confirm_payment' ) {
+ return $url . '/check-payment?order_id=' . $body;
+ }
+ if ( $purpose === 'create_refund' ) {
+ return $url . '/refund';
+ }
+ return $url;
+ }
+
+ /**
+ * Verifying if the url to the backend given in the plugin options is valid or not.
+ *
+ * @param $url - URL to the backend
+ * @return bool - Returns if valid or not.
+ * @since 0.6.0
+ */
+ public function verify_backend_url( $url ): bool
+ {
+ $result = $this->call_api( 'GET', $url, '', '' );
+ if ( $result['result'] ){
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Processes the payment after the checkout
+ *
+ * If the payment process finished successfully the user is being redirected to its GNU Taler Wallet.
+ * If an error occurs it returns void and throws an error.
+ *
+ * @param $order_id - ID of the order to get the Order from the WooCommerce Webshop
+ * @return array|void - Array with result => success and redirection url otherwise it returns void.
+ * @since 0.6.0
+ */
+ public function process_payment( $order_id )
+ {
+ // we need it to get any order detailes
+ $wc_order = wc_get_order( $order_id );
+
+ if ( is_user_logged_in() )
+ {
+ $user_id = WC()->customer->get_id();
+ }
+ else
+ {
+ $user_id = 'Guest';
+ $this->add_log_entry( 'transaction', 'The customer started a transaction without login, therefore the userid is unknown.' );
+ }
+
+ // Gets the url of the backend from the WooCommerce Settings
+ $backend_url = $this->get_option( 'GNU_Taler_Backend_URL', 1 );
+
+ //Log entry that the customer started the payment process
+ $this->add_log_entry( 'transaction', 'Userid: ' . $user_id . ' - Orderid: ' . $order_id . ' - User started the payment process.' );
+
+ if ( ! $this->verify_backend_url( $backend_url ) ) {
+ wc_add_notice( 'Something went wrong please contact the system administrator of the webshop and send the following error: GNU Taler backend url invalid', 'error' );
+ $this->add_log_entry( 'error', 'Userid: ' . $user_id . ' - Orderid: ' . $order_id . ' - Checkout process failed - Invalid backend url.' );
+ return;
+ }
+ $order_json = $this->convert_to_checkout_json( $order_id );
+
+ $this->add_log_entry( 'transaction', 'Userid: ' . $user_id . ' - Orderid: ' . $order_id . ' - Transaction request send to GNU Taler backend' );
+ $order_request = $this->send_order_request( $backend_url, $order_json, $user_id, $order_id );
+
+ if ( $order_request['boolean'] ) {
+
+ //Returns that the payment process finished successfully and redirects the costumer to confirm the payment via GNU Taler
+ $this->add_log_entry( 'transaction', 'Userid: ' . $user_id . ' - Orderid: ' . $order_id . ' - Customer is being redirected to the payment confirmation site' );
+ return array(
+ 'result' => 'success',
+ // 'redirect' => '',
+ 'redirect' => $order_request['url'],
+ );
+ }
+ wc_add_notice( 'There seems to be a problem with the payment process, please try again or send the following message to a system administrator: ' . $order_request['http_code'] . ' - ' . $order_request['error_message'] );
+ $this->add_log_entry( 'error', 'Userid: ' . $user_id . ' - Orderid: ' . $order_id . ' - An error occurred during the payment process - ' . $order_request['http_code'] . ' - ' . $order_request['error_message'] );
+ $wc_order->set_status( 'cancelled' );
+ return;
+ }
+
+ /**
+ * Sends the transaction to the GNU Taler Backend
+ *
+ * If the payment process finishes successfully it returns an array with the redirection url to the GNU Taler Wallet and a boolean value for error handling.
+ * If an error occurs it returns an array with a boolean value for error handling, the http status code and an error message.
+ *
+ * @param $backend_url - URL where the request will be sent.
+ * @param $json - JSON array with the data of the order for the backend.
+ * @param $user_id - User id for logging.
+ * @param $order_id - Order id for logging.
+ * @return array|void - Array with boolean true|false, url or error message with http status code.
+ * @since 0.6.0
+ */
+ public function send_order_request( $backend_url, $json, $user_id, $order_id ): array
+ {
+ // Send the POST-Request via CURL to the GNU Taler Backend
+ $order_confirmation = $this->call_api( 'POST', $backend_url, json_encode($json, JSON_UNESCAPED_SLASHES), 'create_order' );
+
+ $order_message = $order_confirmation['message'];
+ $order_boolean = $order_confirmation['result'];
+
+ if ( $order_boolean ) {
+ $order_confirmation_id = explode( '"', $order_message )[3];
+
+ // Send the final confirmation to execute the payment transaction to the GNU Taler Backend
+ $payment_confirmation = $this->call_api( 'GET', $backend_url, $order_confirmation_id, 'confirm_payment' );
+ $payment_message = $payment_confirmation['message'];
+ $payment_boolean = $order_confirmation['result'];
+
+ if ( $payment_boolean ) {
+
+ //Here we check what kind of http code came back from the backend
+ $payment_confirmation_url = explode( '"', $payment_message )[3];
+ $this->add_log_entry( 'transaction', 'Userid: ' . $user_id . ' - Orderid: ' . $order_id . ' - Successfully received redirect url to wallet from GNU Taler Backend' );
+ return array(
+ 'boolean' => true,
+ 'url' => $payment_confirmation_url,
+ );
+ }
+ $this->add_log_entry( 'error', 'Userid: ' . $user_id . ' - Orderid: ' . $order_id . ' - An error occurred during the second request to the GNU Taler backend - ' . $payment_confirmation['http_code'] . ' - ' . $payment_message );
+ return array(
+ 'boolean' => false,
+ 'http_code' => $payment_confirmation['http_code'],
+ 'error_message' => $payment_message,
+ );
+ }
+ $this->add_log_entry( 'error', 'Userid: ' . $user_id . ' - Orderid: ' . $order_id . ' - An error occurred during the first request to the GNU Taler backend - ' . $order_confirmation['http_code'] . ' - ' . $order_message );
+ return array(
+ 'boolean' => false,
+ 'http_code' => $order_confirmation['http_code'],
+ 'error_message' => $order_message,
+ );
+ }
+
+ /**
+ * Converts the order into a JSON format that can be send to the GNU Taler Backend.
+ *
+ *
+ * The amount of the refund request can, at the moment, only be refunded in the currency 'KUDOS', which is the currency that the GNU Taler Payment system uses.
+ * This will change in the future.
+ *
+ * @param $order_id - To get the order from the WooCommerce Webshop
+ * @return array - return the JSON Format.
+ * @since 0.6.0
+ */
+ public function convert_to_checkout_json( $order_id ): array
+ {
+ $wc_order = wc_get_order( $order_id );
+ $wc_order_total_amount = $wc_order->get_total();
+ $wc_order_currency = $wc_order->get_currency();
+ $wc_cart = WC()->cart->get_cart();
+ $wc_order_id = $wc_order->get_order_key() . '-' . $wc_order->get_order_number();
+ $merchant_option = $this->get_option( 'merchant_information' );
+
+ $wc_order_products_array = $this->mutate_products_to_json_format( $wc_cart, $wc_order_currency, $wc_order);
+
+ $wc_order_merchant = $this->mutate_merchant_information_to_json_format( $merchant_option );
+
+ $order_json = array(
+ 'order' => array(
+ 'amount' => $wc_order_currency . ':' . $wc_order_total_amount,
+ 'summary' => 'Order from the merchant ' . $this->get_option('merchant_name') . ': ',
+ 'fulfillment_url' => get_home_url() . '/wc-api/wc_gnutaler_gateway',
+ //'payment_url' => $this->get_option( 'Payment_url' ),
+ 'order_id' => $wc_order_id,
+ 'merchant' => $wc_order_merchant,
+ 'products' => $wc_order_products_array,
+ ),
+ );
+ return $order_json;
+ }
+
+ /**
+ * Mutates the products in the cart into a format which can be included in a JSON file.
+ *
+ * @param $wc_cart - The content of the WooCommerce Cart.
+ * @param $wc_order_currency - The currency the WooCommerce Webshop uses.
+ * @return array - Returns an array of products.
+ * @since 0.6.0
+ */
+ public function mutate_products_to_json_format( $wc_cart, $wc_order_currency, $wc_order ): array
+ {
+ $wc_order_products_array = array();
+ foreach ( $wc_cart as $product ) {
+ $wc_order_products_array[] = array(
+ 'description' => 'Order of product: ' . $product['data']->get_title(),
+ 'quantity' => $product['quantity'],
+ 'price' => $wc_order_currency . ':' . $product['data']->get_price(),
+ 'product_id' => $product['data']->get_id(),
+ 'delivery_location' => $this->mutate_shipping_information_to_json_format($wc_order),
+ );
+ }
+ return $wc_order_products_array;
+ }
+
+ /**
+ * Mutates the merchant information of the webshop into a format which can be included in a JSON file.
+ *
+ * @param $merchant_option - If the webshop owner allows to send the backend their information
+ * @return array - Returns an array of merchant information's.
+ * @since 0.6.0
+ */
+ public function mutate_merchant_information_to_json_format( $merchant_option ): array
+ {
+ $whitechar_encounter = false;
+ $store_address_street = '';
+ $store_address_streetNr = '';
+
+ // When the option is enabled the informations of the merchant will be included in the transaction
+ if ( $merchant_option === 'yes' ) {
+ // The country/state
+ $store_raw_country = get_option( 'woocommerce_default_country' );
+ $split_country = explode( ':', $store_raw_country );
+
+ // Country and state separated:
+ $store_country = $split_country[0];
+ $store_state = $split_country[1];
+
+ //Streetname and number
+ $store_address = get_option( 'woocommerce_store_address' );
+ $store_address_inverted = strrev( $store_address );
+ $store_address_array = str_split( $store_address_inverted );
+
+ //Split the address into street and street number
+ foreach ( $store_address_array as $char ) {
+ if ( ! $whitechar_encounter ) {
+ $store_address_streetNr .= $char;
+ } elseif ( ctype_space( $char ) ) {
+ $whitechar_encounter = true;
+ } else {
+ $store_address_street .= $char;
+ }
+ }
+ $wc_order_merchant_location = array(
+ 'country' => $store_country,
+ 'state' => $store_state,
+ 'city' => WC()->countries->get_base_city(),
+ 'ZIP code' => WC()->countries->get_base_postcode(),
+ 'street' => strrev( $store_address_street ),
+ 'street number' => strrev( $store_address_streetNr ),
+ );
+ return array(
+ 'address' => $wc_order_merchant_location,
+ 'name' => $this->get_option( 'merchant_name' ),
+ );
+ }
+ return array();
+ }
+
+ /**
+ * Processes the refund transaction if requested by the system administrator of the webshop
+ *
+ * If the refund request is finished successfully it returns an refund url, which can be send to the customer to finish the refund transaction.
+ * If an error it will throw a WP_Error message and inform the system administrator.
+ *
+ * @param $wc_order
+ * @return array
+ * @since 0.6.0
+ */
+ public function mutate_shipping_information_to_json_format($wc_order): array
+ {
+ $whitechar_encounter = false;
+ $shipping_address_street = '';
+ $shipping_address_streetNr = '';
+
+ $store_address = $wc_order->get_shipping_address_1();
+ $store_address_inverted = strrev( $store_address );
+ $store_address_array = str_split( $store_address_inverted );
+
+ //Split the address into street and street number
+ foreach ( $store_address_array as $char ) {
+ if ( ! $whitechar_encounter ) {
+ $shipping_address_street .= $char;
+ } elseif ( ctype_space( $char ) ) {
+ $whitechar_encounter = true;
+ } else {
+ $shipping_address_street .= $char;
+ }
+ }
+
+ return array(
+ 'country' => $wc_order->get_shipping_country(),
+ 'state' => $wc_order->get_shipping_state(),
+ 'city' => $wc_order->get_shipping_city(),
+ 'ZIP code' => $wc_order->get_shipping_postcode(),
+ 'street' => $shipping_address_street,
+ 'street number' => $shipping_address_streetNr,
+ );
+ }
+
+ /**
+ * Processes the refund transaction if requested by the system administrator of the webshop
+ *
+ * If the refund request is finished successfully it returns an refund url, which can be send to the customer to finish the refund transaction.
+ * If an error it will throw a WP_Error message and inform the system administrator.
+ *
+ * @param $order_id - Order id for logging.
+ * @param null $amount - Amount that is requested to be refunded.
+ * @param string $reason - Reason for the refund request.
+ * @return bool|WP_Error - Returns true or throws an WP_Error message in case of error.
+ * @since 0.6.0
+ */
+ public function process_refund( $order_id, $amount = null, $reason = '' )
+ {
+ $wc_order = wc_get_order( $order_id );
+ $refund_json = $this->convert_refund_to_json( $wc_order, $amount, $reason );
+
+ $user_id = wc_get_order($order_id)->get_customer_id();
+ if ( $user_id === 0 ){
+ $user_id = 'Guest';
+ }
+
+ $this->add_log_entry( 'transaction', 'Userid: ' . $user_id . ' - Orderid: ' . $order_id . ' - Refund process of order: ' . $order_id . ' started with the refunded amount: ' . $amount . ' ' . $wc_order->get_currency() . ' and the reason: ' . $reason );
+
+ // Gets the url of the backend from the WooCommerce Settings
+ $backend_url = $this->get_option( 'GNU_Taler_Backend_URL' );
+
+ //Get the current status of the order
+ $wc_order_status = $wc_order->get_status();
+
+ //Checks if current status is already set as paid
+ if ( $wc_order_status === 'processing' || $wc_order_status === 'on hold' || $wc_order_status === 'completed' ) {
+
+ $this->add_log_entry( 'transaction', 'Userid: ' . $user_id . ' - Orderid: ' . $order_id . ' - Refund request sent to the GNU Taler Backend' );
+ $refund_request = $this->send_refund_request( $backend_url, $refund_json );
+
+ if( $refund_request['boolean'] ) {
+ //Set the status as refunded and post the link to confirm the refund process via the GNU Taler payment method
+ $wc_order->update_status( 'refunded' );
+ $wc_order->add_order_note( 'The refund process finished successfully, please send the following url to the customer via an email to confirm the refund transaction.' );
+ $wc_order->add_order_note( $refund_request['url'] );
+ $this->add_log_entry( 'transaction', 'Userid: ' . $user_id . ' - Orderid: ' . $order_id . ' - Successfully received refund redirect url from GNU Taler backend, customer can now refund the given amount.' );
+ return true;
+ }
+ $this->add_log_entry( 'error', 'Userid: ' . $user_id . ' - Orderid: ' . $order_id . ' - An error occurred during the refund process - ' . $refund_request['http_code'] . ' - ' . $refund_request['error_message'] );
+ return new WP_Error( 'error', 'An error occurred during the refund process, please try again or send the following message to your system administrator: ' . $refund_request['http_code'] . ' - ' . $refund_request['error_message'] );
+ }
+ $this->add_log_entry( 'error', 'Userid: ' . $user_id . ' - Orderid: ' . $order_id . ' - The status of the order does not allow a refund' );
+ return new WP_Error( 'error', 'The status of the order does not allow for a refund.' );
+ }
+
+ /**
+ * Sends the refund transaction to the GNU Taler Backend
+ *
+ * If the refund process finishes successfully it returns a boolean value true and sends the system administrator the refund url for the customer.
+ * If an error occurs it returns a WP_Error which will be displayed .
+ *
+ * @param $backend_url - URL where the request will be sent.
+ * @param $json - JSON array with the data of the refund request for the backend.
+ * @return array|void - Array with boolean true|false, url or error message with http status code.
+ * @since 0.6.0
+ */
+ public function send_refund_request( $backend_url, $json ): array
+ {
+ $refund_url = '';
+ $refund_confirmation = $this->call_api( 'POST', $backend_url, json_encode($json, JSON_UNESCAPED_SLASHES), 'create_refund' );
+
+ $message = $refund_confirmation['message'];
+ $refund_boolean = $refund_confirmation['result'];
+
+ if ($refund_boolean) {
+ //Here we check what kind of http code came back from the backend
+ $refund_confirmation_array = explode(',', $message);
+ foreach ( $refund_confirmation_array as $value ) {
+
+ //Looping through the return value and checking if "refund_redirect_url" can be found
+ if ( strpos( $value, 'refund_redirect_url' ) ) {
+ $refund_url = explode( '"', $value )[3];
+ }
+ }
+ return array(
+ 'boolean' => true,
+ 'url' => $refund_url,
+ );
+ }
+ return array(
+ 'boolean' => false,
+ 'url' => $refund_url,
+ 'http_code' => $refund_confirmation['http_code'],
+ 'error_message' => $refund_confirmation['message'],
+ );
+ }
+
+ /**
+ * Converts the information of the refund request into a JSON format that can be send to the GNU Taler Backend.
+ *
+ * The amount of the refund request can, at the moment, only be refunded in the currency 'KUDOS', which is the currency that the GNU Taler Payment system uses.
+ * This will change in the future.
+ *
+ * @param $order - Order where the refund request originated from.
+ * @param $amount - Amount to be refunded.
+ * @param $reason - Reason of refund.
+ * @return array - returns the JSON Format.
+ * @since 0.6.0
+ */
+ public function convert_refund_to_json( $order, $amount, $reason ): array
+ {
+ return array(
+ 'order_id' => $order->get_order_key() . '-' . $order->get_order_number(),
+ 'refund' => $order->get_currency() . ':' . $amount,
+ 'instance' => 'default',
+ 'reason' => $reason,
+ );
+ }
+
+ /**
+ *
+ * Creates or opens the log files and writes a log entry.
+ *
+ * @param $type - What kind of log it is.
+ * @param $message - What the message of the log entry is.
+ * @return void - Returns void.
+ * @since 0.6.0
+ */
+ public function add_log_entry( $type, $message ): void
+ {
+ $file = null;
+ $timestamp = date( 'r' );
+ if ( $type === 'error' ) {
+ $file = fopen( __DIR__ . '/log/GNUTaler_Error.log', 'ab' );
+ }
+ elseif ( $type === 'transaction' ) {
+ $file = fopen( __DIR__ . '/log/GNUTaler_User_Transactions.log', 'ab' );
+ }
+ else
+ {
+ $file = fopen( __DIR__ . '/log/GNUTaler_' . $type . '.log', 'ab' );
+ }
+ if ( $file !== null ){
+ fwrite( $file, $timestamp . ' - ' . $message . PHP_EOL );
+ fclose( $file );
+ }
+ }
+ }
+}
diff --git a/plugin/src/GNU-taler-payment/functions/functions.php b/plugin/src/GNU-taler-payment/functions/functions.php
new file mode 100644
index 0000000..1a8dd6f
--- /dev/null
+++ b/plugin/src/GNU-taler-payment/functions/functions.php
@@ -0,0 +1,224 @@
+<?php
+
+/**
+ * Sends a request to a url via HTTP.
+ *
+ * Sends a request to a GNU Taler Backend over HTTP and returns the result.
+ * The request can be sent as POST, GET, PUT or another method.
+ *
+ * @param $method - POST, GET, PUT or another method.
+ * @param $backend_url - URL to the GNU Taler Backend.
+ * @param $body - The content of the request.
+ * @param $purpose - What return value is to be expected.
+ * @param $api_key
+ * @return array The return array will either have the successful return value or a detailed error message.
+ * @since 0.6.0
+ */
+function call_api( $method, $backend_url, $body, $purpose, $api_key ): array
+{
+ //create_url
+ $url = create_api_url( $backend_url, $purpose, $body );
+
+ //Initialize curl request
+ $curl = curl_init_request( $method, $body, $url, $api_key);
+
+ // EXECUTE:
+ $result = curl_exec( $curl );
+
+ //HTTP Status Error handling
+ $message_array = curl_error_handling( $curl, $result );
+ curl_close( $curl );
+ return $message_array;
+}
+
+/**
+ * Checks if the return http code is a success and if not what kind of error status it is.
+ *
+ * If the request was successful an array will be returned with the boolean value true, the http code and the result of the response.
+ * If the request failed an array will be returned with the boolean value false, the http code and a detailed error message.
+ *
+ * @param $curl - Created curl request for error handling.
+ * @param $result - The response from the backend, that will be returned if the request was successful
+ * @return array - Array with a boolean, a http code and a message will be returned
+ * @since 0.6.0
+ *
+ */
+function curl_error_handling( $curl, $result ): array
+{
+ $http_code = curl_getinfo( $curl, CURLINFO_HTTP_CODE );
+ if ( curl_error( $curl ) ) {
+ $error_msg = curl_error( $curl );
+ }
+ if ( isset( $error_msg ) ) {
+ return array(
+ 'result' => false,
+ 'http_code' => $http_code,
+ 'message' => $error_msg,
+ );
+ }
+ if ( $http_code === 200 ) {
+ return array(
+ 'result' => true,
+ 'http_code' => $http_code,
+ 'message' => $result,
+ );
+ }
+ if ( preg_match( '(4[0-9]{2})', $http_code ) ) {
+ switch ($http_code) {
+ case 400:
+ return array(
+ 'result' => false,
+ 'http_code' => $http_code,
+ 'message' => 'Bad request',
+ );
+ break;
+ case 401:
+ return array(
+ 'result' => false,
+ 'http_code' => $http_code,
+ 'message' => 'Unauthorized',
+ );
+ break;
+ case 403:
+ return array(
+ 'result' => false,
+ 'http_code' => $http_code,
+ 'message' => 'Forbidden',
+ );
+ break;
+ case 404:
+ return array(
+ 'result' => false,
+ 'http_code' => $http_code,
+ 'message' => 'Page Not Found',
+ );
+ break;
+ default:
+ return array(
+ 'result' => false,
+ 'http_code' => $http_code,
+ 'message' => '4xx Client Error',
+ );
+ break;
+ }
+ } elseif ( preg_match( '(5[0-9]{2})', $http_code ) ) {
+ switch ( $http_code ) {
+ case '500':
+ return array(
+ 'result' => false,
+ 'http_code' => $http_code,
+ 'message' => 'Internal Server Error',
+ );
+ break;
+ case '502':
+ return array(
+ 'result' => false,
+ 'http_code' => $http_code,
+ 'message' => 'Bad Gateway',
+ );
+ break;
+ case '503':
+ return array(
+ 'result' => false,
+ 'http_code' => $http_code,
+ 'message' => 'Service Unavailable',
+ );
+ break;
+ case '504':
+ return array(
+ 'result' => false,
+ 'http_code' => $http_code,
+ 'message' => 'Gateway Timeout',
+ );
+ break;
+ default:
+ return array(
+ 'result' => false,
+ 'http_code' => $http_code,
+ 'message' => '5xx Client Error',
+ );
+ break;
+ }
+ } else {
+ return array(
+ 'result' => false,
+ 'http_code' => $http_code,
+ 'message' => 'http status error',
+ );
+ }
+}
+
+/**
+ * Initialises the curl request and sets some necessary options depending on the method.
+ *
+ * Depending of the method chosen different options for the curl request will be set.
+ * Not depending on the method the settings for a return value, Authorization and Content-Type are being set.
+ *
+ * @param $method - POST, GET, PUT or another method.
+ * @param $body - Content of the request.
+ * @param $url - URL where the request will be send
+ * @param $api_key
+ * @return false|resource - Either the configured curl request will be returned or false if an error appears.
+ * @since 0.6.0
+ */
+function curl_init_request( $method, $body, $url, $api_key )
+{
+ $curl = curl_init();
+
+ switch ( $method ) {
+ case 'POST':
+ curl_setopt( $curl, CURLOPT_POST, 1 );
+ if ( $body ) {
+ curl_setopt( $curl, CURLOPT_POSTFIELDS, $body );
+ }
+ break;
+ case 'PUT':
+ curl_setopt( $curl, CURLOPT_CUSTOMREQUEST, 'PUT' );
+ if ( $body ) {
+ curl_setopt( $curl, CURLOPT_POSTFIELDS, $body );
+ }
+ break;
+ case 'GET':
+ curl_setopt( $curl, CURLOPT_VERBOSE, 1 );
+ break;
+ default:
+ curl_setopt( $curl, CURLOPT_CUSTOMREQUEST, $method );
+ break;
+ }
+
+ // OPTIONS:
+ curl_setopt( $curl, CURLOPT_URL, $url );
+ curl_setopt( $curl, CURLOPT_HTTPHEADER, array(
+ 'Authorization: ' . $api_key,
+ 'Content-Type: application/json',
+ ) );
+ curl_setopt( $curl, CURLOPT_RETURNTRANSFER, 1 );
+ curl_setopt ($curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC );
+
+ return $curl;
+}
+
+/**
+ * Creates the final url depending on the purpose.
+ *
+ * @param $url - URL where the request will be send.
+ * @param $purpose - What will be added to the url.
+ * @param $body - Content of the request.
+ * @return string - return the final url.
+ * @since 0.6.0
+ */
+function create_api_url ($url, $purpose, $body ): string
+{
+ if ( $purpose === 'create_order' ) {
+ return $url . '/order';
+ }
+ if ( $purpose === 'confirm_payment' ) {
+ return $url . '/check-payment?order_id=' . $body;
+ }
+ if ( $purpose === 'create_refund' ) {
+ return $url . '/refund';
+ }
+ return $url;
+}
+
+
diff --git a/plugin/src/GNU-taler-payment/functions/functionsTest.php b/plugin/src/GNU-taler-payment/functions/functionsTest.php
new file mode 100644
index 0000000..a18dab2
--- /dev/null
+++ b/plugin/src/GNU-taler-payment/functions/functionsTest.php
@@ -0,0 +1,157 @@
+<?php
+
+
+use PHPUnit\Framework\Assert;
+use PHPUnit\Framework\TestCase;
+require 'functions.php';
+
+
+/**
+ * Class functionsTest
+ */
+class functionsTest extends TestCase
+{
+ /**
+ * Tests the call_api function
+ */
+ public function test_call_api(): void
+ {
+ $method_post = 'POST';
+ $method_get = 'GET';
+ $method_different = '1234';
+ $wc_order_test_request = '';
+ $backend_url = 'https://backend.demo.taler.net';
+ $api_key = 'ApiKey sandbox';
+
+ try {
+ $wc_order_test_request = 'wc_test_' . random_int(0, 1000);
+ } catch (Exception $e) {
+ }
+ $body_request_1 = array(
+ 'order' => array(
+ 'amount' => 'KUDOS:0.1',
+ 'fulfillment_url' => 'http://gnutaler.hofmd.ch',
+ 'summary' => 'Test_order',
+ 'order_id' => $wc_order_test_request,
+ )
+ );
+ $purpose_1 = 'create_order';
+
+ $body_request_2 = $wc_order_test_request;
+ $purpose_2 = 'confirm_payment';
+
+ $result_create_order = call_api( $method_post, $backend_url, json_encode($body_request_1), $purpose_1, $api_key );
+ $result_confirm_payment = call_api( $method_get, $backend_url, $body_request_2, $purpose_2, $api_key );
+ $result_verify_backend_url = call_api( $method_get, $backend_url, '', '', $api_key );
+ $result_method_different = call_api( $method_different, $backend_url, json_encode($body_request_1), $purpose_1, $api_key );
+
+ Assert::assertTrue($result_create_order['result']);
+ Assert::assertEquals($wc_order_test_request, json_decode($result_create_order['message'], true)['order_id']);
+ Assert::assertTrue($result_confirm_payment['result']);
+ Assert::assertEquals(false, json_decode($result_confirm_payment['message'], true)['paid']);
+ Assert::assertTrue($result_verify_backend_url['result']);
+ Assert::assertEquals('Hello, I\'m a merchant\'s Taler backend. This HTTP server is not for humans.', trim($result_verify_backend_url['message']));
+ Assert::assertFalse($result_method_different['result']);
+ Assert::assertEquals('Bad request', $result_method_different['message']);
+ }
+
+
+ /**
+ * Tests the create_api_url function
+ */
+ public function test_create_api_url(): void
+ {
+ $url_test = 'https://backend.demo.taler.net';
+ $wc_test_order = '';
+ try {
+ $wc_test_order = 'wc_test_' . random_int(0, 1000);
+ } catch (Exception $e) {
+ }
+ $purpose_create_order = 'create_order';
+ $purpose_confirm_payment = 'confirm_payment';
+ $purpose_create_refund = 'create_refund';
+
+ $create_order_url = create_api_url($url_test, $purpose_create_order, '');
+ $confirm_payment_url = create_api_url($url_test, $purpose_confirm_payment, $wc_test_order);
+ $create_refund_url = create_api_url($url_test, $purpose_create_refund, '');
+
+ Assert::assertEquals('https://backend.demo.taler.net/order', $create_order_url);
+ Assert::assertEquals('https://backend.demo.taler.net/check-payment?order_id=' . $wc_test_order, $confirm_payment_url);
+ Assert::assertEquals('https://backend.demo.taler.net/refund', $create_refund_url);
+ }
+
+ /**
+ * Tests the curl_error_handling function with the http status code 200
+ */
+ public function test_curl_error_handling_code_200(): void
+ {
+ $api_key = 'ApiKey sandbox';
+ $test_url = 'https://backend.demo.taler.net';
+
+ $curl_error_message_array = call_api('GET', $test_url, '', '', $api_key);
+
+ Assert::assertTrue($curl_error_message_array['result']);
+ Assert::assertEquals(200, $curl_error_message_array['http_code']);
+ }
+
+ /**
+ * Tests the curl_error_handling function with the http status code 400
+ */
+ public function test_curl_error_handling_code_400(): void
+ {
+ $api_key = 'ApiKey sandbox';
+ $api_key_wrong = 'ApiKey ____***££££èèè';
+ $test_url = 'https://backend.demo.taler.net';
+ $test_url_wrong = 'https://backend.demo.taler.net/test_if_this_exits';
+ $body = json_encode(array(
+ 'order' => array(
+ 'wrong_field' => 'Wrong value',
+ )
+ ));
+
+ $curl_error_message_array_400 = call_api('POST', $test_url, $body, 'create_order', $api_key);
+ $curl_error_message_array_401 = call_api('GET', $test_url, '', '', $api_key_wrong);
+ $curl_error_message_array_403 = call_api('GET', 'https://httpstat.us/403', '', '', '');
+ $curl_error_message_array_404 = call_api('GET', $test_url_wrong, '', '', $api_key);
+
+ Assert::assertFalse($curl_error_message_array_400['result']);
+ Assert::assertEquals(400, $curl_error_message_array_400['http_code']);
+ Assert::assertFalse($curl_error_message_array_401['result']);
+ Assert::assertEquals(401, $curl_error_message_array_401['http_code']);
+ Assert::assertFalse($curl_error_message_array_403['result']);
+ Assert::assertEquals(403, $curl_error_message_array_403['http_code']);
+ Assert::assertFalse($curl_error_message_array_404['result']);
+ Assert::assertEquals(404, $curl_error_message_array_404['http_code']);
+
+ }
+
+
+ /**
+ * Tests the curl_error_handling function with the http status code 500
+ */
+ public function test_curl_error_handling_code_500(): void
+ {
+ $api_key = 'ApiKey sandbox';
+ $test_url = 'https://backend.demo.taler.net';
+ $test_url_500 = 'https://httpstat.us/500';
+ $test_url_502 = 'https://httpstat.us/502';
+ $test_url_503 = 'https://httpstat.us/503';
+ $test_url_504 = 'https://httpstat.us/504';
+
+ $curl_error_message_array_500 = call_api('GET', $test_url_500, '', '', $api_key);
+ $curl_error_message_array_502 = call_api('GET', $test_url_502, '', '', $api_key);
+ $curl_error_message_array_503 = call_api('GET', $test_url_503, '', '', $api_key);
+ $curl_error_message_array_504 = call_api('GET', $test_url_504, '', '', $api_key);
+
+ Assert::assertFalse($curl_error_message_array_500['result']);
+ Assert::assertEquals(500, $curl_error_message_array_500['http_code']);
+ Assert::assertFalse($curl_error_message_array_502['result']);
+ Assert::assertEquals(502, $curl_error_message_array_502['http_code']);
+ Assert::assertFalse($curl_error_message_array_503['result']);
+ Assert::assertEquals(503, $curl_error_message_array_503['http_code']);
+ Assert::assertFalse($curl_error_message_array_504['result']);
+ Assert::assertEquals(504, $curl_error_message_array_504['http_code']);
+
+ }
+
+}
diff --git a/plugin/src/GNU-taler-payment/js/WalletDetection.js b/plugin/src/GNU-taler-payment/js/WalletDetection.js
new file mode 100644
index 0000000..d2b1df5
--- /dev/null
+++ b/plugin/src/GNU-taler-payment/js/WalletDetection.js
@@ -0,0 +1,43 @@
+/**
+ * Wallet detection script
+ * Detects which browser the user is using and if the GNU Taler wallet is installed
+ * If the wallet isn't detected or the customer uses a browser which isn't supported, then it removes the GNU Taler payment method from the possibilities.
+ *
+ * Currently only the Browser detection is working and the wallet detection isn't
+ * The reason is, that we couldn't figure out how to detect the wallet with the given functions of the taler-wallet-lib.js
+ */
+
+function detectWallet() {
+
+ sUsrAg = navigator.userAgent;
+
+ if ((sUsrAg.indexOf("Firefox") > -1) || (sUsrAg.indexOf("Opera") > -1 || sUsrAg.indexOf("OPR") > -1) || (sUsrAg.indexOf("Chrome") > -1)) {
+ //Mozilla Firefox, Opera or Google Chrome
+ taler.onAbsent(() => {
+ //Does nothing
+ });
+ } else if ((sUsrAg.indexOf("Trident") > -1) || (sUsrAg.indexOf("Edge") > -1) || (sUsrAg.indexOf("Safari") > -1)) {
+ //Microsoft Internet Explorer, Microsoft edge or Apple Safari
+ removePaymentMethod();
+ } else {
+ //Unknown Browser
+ removePaymentMethod();
+ }
+}
+
+function removePaymentMethod() {
+ var observer = new MutationObserver(function (mutations, observer) {
+ mutations.forEach(() => {
+ document.getElementsByClassName("wc_payment_method payment_method_gnutaler").item(0).style.display = 'none';
+ });
+ });
+
+ // define what element should be observed by the observer
+ // and what types of mutations trigger the callback
+ observer.observe(document, {
+ subtree: true,
+ attributes: true
+ });
+}
+
+detectWallet(); \ No newline at end of file
diff --git a/plugin/src/GNU-taler-payment/js/taler-wallet-lib.js b/plugin/src/GNU-taler-payment/js/taler-wallet-lib.js
new file mode 100644
index 0000000..8b1812a
--- /dev/null
+++ b/plugin/src/GNU-taler-payment/js/taler-wallet-lib.js
@@ -0,0 +1,270 @@
+/*
+ @source https://www.git.taler.net/?p=web-common.git;a=blob_plain;f=taler-wallet-lib.ts;hb=HEAD
+ @license magnet:?xt=urn:btih:5de60da917303dbfad4f93fb1b985ced5a89eac2&dn=lgpl-2.1.txt LGPL v21
+
+ @licstart The following is the entire license notice for the
+ JavaScript code in this page.
+
+ Copyright (C) 2015, 2016 INRIA
+
+ The JavaScript code in this page is free software: you can
+ redistribute it and/or modify it under the terms of the GNU
+ Lesser General Public License (GNU LGPL) as published by the Free Software
+ Foundation, either version 2.1 of the License, or (at your option)
+ any later version. The code is distributed WITHOUT ANY WARRANTY;
+ without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU LGPL for more details.
+
+ As additional permission under GNU LGPL version 2.1 section 7, you
+ may distribute non-source (e.g., minimized or compacted) forms of
+ that code without the copy of the GNU LGPL normally required by
+ section 4, provided you include this license notice and a URL
+ through which recipients can access the Corresponding Source.
+
+ @licend The above is the entire license notice
+ for the JavaScript code in this page.
+
+ @author Marcello Stanisci
+ @author Florian Dold
+*/
+
+var taler;
+(function (taler) {
+ "use strict";
+ var logVerbose = false;
+ try {
+ logVerbose = !!localStorage.getItem("taler-log-verbose");
+ }
+ catch (e) {
+ // can't read from local storage
+ }
+ var presentHandlers = [];
+ var absentHandlers = [];
+ // Are we running as the content script of an
+ // extension (and not just from a normal page)?
+ var runningInExtension = false;
+ var callSeqId = 1;
+ var installed = false;
+ var probeExecuted = false;
+ var pageLoaded = false;
+ var errorHandler = undefined;
+ function onError(handler) {
+ if (errorHandler) {
+ console.warn("Overriding error handler");
+ }
+ errorHandler = handler;
+ }
+ taler.onError = onError;
+ /**
+ * Error handler for things that go wrong in the merchant
+ * frontend browser code.
+ */
+ function raise_error(reason, detail) {
+ if (errorHandler) {
+ errorHandler(reason, detail);
+ return;
+ }
+ alert("Failure: " + reason + ". No error handler installed. Open the developer console for more information.");
+ console.error(reason, detail);
+ console.warn("No custom error handler set.");
+ }
+ function callWallet(funcName, args, onResult) {
+ var detail = JSON.parse(JSON.stringify(args || {}));
+ var callId = callSeqId++;
+ detail.callId = callId;
+ var onTimeout = function () {
+ console.warn("timeout for invocation of " + funcName);
+ };
+ var timeoutHandle = setTimeout(onTimeout, 1000);
+ var handler = function (evt) {
+ if (evt.detail.callId !== callId) {
+ return;
+ }
+ if (onResult) {
+ onResult(evt.detail);
+ }
+ clearTimeout(timeoutHandle);
+ document.removeEventListener(funcName + "-result", handler);
+ };
+ document.addEventListener(funcName + "-result", handler);
+ var evt = new CustomEvent(funcName, { detail: detail });
+ document.dispatchEvent(evt);
+ }
+ /**
+ * Confirm that a reserve was created.
+ *
+ * Used by tightly integrated bank portals.
+ */
+ function confirmReserve(reservePub) {
+ if (!installed) {
+ logVerbose && console.log("delaying confirmReserve");
+ taler.onPresent(function () {
+ confirmReserve(reservePub);
+ });
+ return;
+ }
+ callWallet("taler-confirm-reserve", { reserve_pub: reservePub });
+ }
+ taler.confirmReserve = confirmReserve;
+ function createReserve(callbackUrl, amount, wtTypes, suggestedExchangeUrl) {
+ if (!installed) {
+ logVerbose && console.log("delaying createReserve");
+ taler.onPresent(function () {
+ createReserve(callbackUrl, amount, wtTypes, suggestedExchangeUrl);
+ });
+ return;
+ }
+ var args = {
+ callback_url: callbackUrl,
+ amount: amount,
+ wt_types: wtTypes,
+ suggested_exchange_url: suggestedExchangeUrl
+ };
+ callWallet("taler-create-reserve", args);
+ }
+ taler.createReserve = createReserve;
+ function onPresent(f) {
+ presentHandlers.push(f);
+ }
+ taler.onPresent = onPresent;
+ function onAbsent(f) {
+ absentHandlers.push(f);
+ }
+ taler.onAbsent = onAbsent;
+ function pay(p) {
+ if (!installed) {
+ logVerbose && console.log("delaying call to 'pay' until GNU Taler wallet is present");
+ taler.onPresent(function () {
+ pay(p);
+ });
+ return;
+ }
+ callWallet("taler-pay", p);
+ }
+ taler.pay = pay;
+ function refund(refundUrl) {
+ if (!installed) {
+ logVerbose && console.log("delaying call to 'refund' until GNU Taler wallet is present");
+ taler.onPresent(function () {
+ refund(refundUrl);
+ });
+ return;
+ }
+ callWallet("taler-refund", refundUrl);
+ }
+ taler.refund = refund;
+ function addAuditor(d) {
+ if (!installed) {
+ logVerbose && console.log("delaying call to 'addAuditor' until GNU Taler wallet is present");
+ taler.onPresent(function () {
+ addAuditor(d);
+ });
+ return;
+ }
+ callWallet("taler-add-auditor", d);
+ }
+ taler.addAuditor = addAuditor;
+ /**
+ * Check if an auditor is already added to the wallet.
+ *
+ * Same-origin restrictions apply.
+ */
+ function checkAuditor(url) {
+ if (!installed) {
+ logVerbose && console.log("delaying call to 'checkAuditor' until GNU Taler wallet is present");
+ return new Promise(function (resolve, reject) {
+ taler.onPresent(function () {
+ resolve(checkAuditor(url));
+ });
+ });
+ }
+ return new Promise(function (resolve, reject) {
+ taler.onPresent(function () {
+ callWallet("taler-check-auditor", url, function (x) { return resolve(x); });
+ });
+ });
+ }
+ taler.checkAuditor = checkAuditor;
+ function initTaler() {
+ function handleUninstall() {
+ installed = false;
+ // not really true, but we want "uninstalled" to be shown
+ firstTimeoutCalled = true;
+ announce();
+ }
+ function handleProbe() {
+ probeExecuted = true;
+ if (!installed) {
+ logVerbose && console.log("taler install detected");
+ installed = true;
+ announce();
+ }
+ }
+ function probeTaler() {
+ probeExecuted = false;
+ var eve = new Event("taler-probe");
+ document.dispatchEvent(eve);
+ }
+ var firstTimeoutCalled = false;
+ function onProbeTimeout() {
+ if (!probeExecuted) {
+ if (installed || !firstTimeoutCalled) {
+ installed = false;
+ firstTimeoutCalled = true;
+ logVerbose && console.log("taler uninstall detected");
+ announce();
+ }
+ }
+ // try again, maybe it'll be installed ...
+ probeTaler();
+ }
+ /**
+ * Announce presence/absence
+ *
+ * Only called after document.readyState is at least "interactive".
+ */
+ function announce() {
+ if (!pageLoaded) {
+ logVerbose && console.log("page not loaded yet, announcing later");
+ return;
+ }
+ if (installed) {
+ logVerbose && console.log("announcing installed");
+ for (var i = 0; i < presentHandlers.length; i++) {
+ presentHandlers[i]();
+ }
+ }
+ else {
+ if (firstTimeoutCalled) {
+ logVerbose && console.log("announcing uninstalled");
+ for (var i = 0; i < absentHandlers.length; i++) {
+ absentHandlers[i]();
+ }
+ }
+ else {
+ logVerbose && console.log("announcing nothing");
+ }
+ }
+ }
+ function onPageLoad() {
+ pageLoaded = true;
+ // We only start the timeout after the page is interactive.
+ window.setInterval(onProbeTimeout, 300);
+ announce();
+ }
+ probeTaler();
+ document.addEventListener("taler-probe-result", handleProbe, false);
+ document.addEventListener("taler-uninstall", handleUninstall, false);
+ // Handle the case where the JavaScript is loaded after the page
+ // has been loaded for the first time.
+ if (document.readyState === "loading") {
+ document.addEventListener("DOMContentLoaded", onPageLoad, false);
+ }
+ else {
+ onPageLoad();
+ }
+ }
+ logVerbose && console.log("running taler-wallet-lib from page");
+ initTaler();
+})(taler || (taler = {}));
+// @license-end \ No newline at end of file
diff --git a/plugin/src/GNU-taler-payment/readme.txt b/plugin/src/GNU-taler-payment/readme.txt
new file mode 100644
index 0000000..e298a0e
--- /dev/null
+++ b/plugin/src/GNU-taler-payment/readme.txt
@@ -0,0 +1,59 @@
+=== GNU Taler Payment Gateway for Woocommerce ===
+Contributors: hofmd2, sakaeo
+Donate link: https://donations.demo.taler.net/
+Tags: woocommerce, e-commerce, GNU Taler, Taler, Payment Gateway
+Requires at least: 5.1
+Tested up to: 5.2.1
+Stable tag: 5.2
+Requires PHP: 7.2
+License: GNU General Public License v3.0
+License URI: http://www.gnu.org/licenses/gpl-3.0.html
+
+Online payment plugin for Woocommerce powered by GNU Taler
+
+== Description ==
+
+This plugin provides a safe and secure way to pay via the GNU Taler system. The plugin sends a request to and receives a respones from the GNU Taler Backend.
+After that the plugin confirms the transaction again and redirect the customer to his own wallet to confirm the transaction.
+The plugin provides the possibilitiy for the admininstrator to send the costumer a refund.
+For that the plugin sends a refund request to the GNU Taler backend and receives a refund-url, which will be forwarded to the customer via an email to confirm the refund.
+
+The GNU Taler payment system has some certificate and includes latest fraud and risk management.
+
+== Installation ==
+
+1. Ensure you have latest version of WooCommerce plugin installed
+2. Upload the plugin files to the `/wp-content/plugins/plugin-name` directory, or install the plugin through the WordPress plugins screen directly.
+3. Activate the GNU Taler Payment for Woocommerce plugin through the 'Plugins' screen in WordPress.
+4. Use WooCommerce settings-> payment tab -> GNU Taler Payment for Woocommerce Settings to configure the plugin.
+
+== Frequently Asked Questions ==
+
+= Do I have to have a GNU Taler account to use the plugin? =
+
+Yes, you need to have an account.
+You can join the GNU Taler family on: https://bank.demo.taler.net/
+
+= Does the customer need to have the GNU Taler Wallet installed to pay with GNU Taler? =
+
+Yes, the customer needs the GNU Taler Wallet.
+The customer can download it here: https://bank.demo.taler.net/
+
+
+= Can the plugin work without Woocommerce =
+
+For the plugin to work perfectly you need to have the Woocommerce plugin installed
+
+== Screenshots ==
+
+1. No screenshots
+
+== Changelog ==
+
+= 0.6.0 =
+* First Public Release
+
+== Upgrade Notice ==
+
+= 0.6.0 =
+