diff options
Diffstat (limited to 'plugin/src/GNU-taler-payment')
-rw-r--r-- | plugin/src/GNU-taler-payment/class-wc-gnutaler-gateway.php | 890 | ||||
-rw-r--r-- | plugin/src/GNU-taler-payment/functions/functions.php | 224 | ||||
-rw-r--r-- | plugin/src/GNU-taler-payment/functions/functionsTest.php | 157 | ||||
-rw-r--r-- | plugin/src/GNU-taler-payment/js/WalletDetection.js | 43 | ||||
-rw-r--r-- | plugin/src/GNU-taler-payment/js/taler-wallet-lib.js | 270 | ||||
-rw-r--r-- | plugin/src/GNU-taler-payment/readme.txt | 59 |
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 = + |