gnu-taler-payment-for-joomla-payage

Integration of GNU Taler payments into Joomla! e-commerce framework
Log | Files | Refs | README | LICENSE

taler_leibacher.php (19593B)


      1 <?php
      2 /**
      3  * @version     1.0.0
      4 
      5  * @date        2023-05-29
      6  * @copyright   2023 Tim Leibacher
      7  * @license     https://www.gnu.org/licenses/old-licenses/gpl-2.0.html GNU/GPLv2
      8  */
      9 defined("_JEXEC") or die("Restricted Access");
     10 
     11 use Joomla\CMS\Uri\Uri;
     12 
     13 /**
     14  * @since     1.0.0
     15  */
     16 class PayageModelTaler_Leibacher extends PayageModelAccount
     17 {
     18 	/**
     19 	 * Default response timeout (in seconds).
     20 	 */
     21 	public const DEFAULT_TIMEOUT = 10;
     22 	/**
     23 	 * Default connect timeout (in seconds).
     24 	 */
     25 	public const DEFAULT_CONNECT_TIMEOUT = 5;
     26 
     27 	/**
     28 	 * HTTP Methods
     29 	 */
     30 	public const HTTP_GET = "GET";
     31 	public const HTTP_POST = "POST";
     32 
     33 	var $app = null;
     34 
     35 	var $common_data = null;
     36 
     37 	var $specific_data = null;
     38 
     39 	function __construct()
     40 	{
     41 		parent::__construct();
     42 		$xml_array = JInstaller::parseXMLInstallFile(JPATH_ADMINISTRATOR . '/components/com_payage/payage_taler_leibacher.xml');
     43 		$this->gw_addon_version = $xml_array['version'];
     44 		LAPG_trace::trace("Taler: v" . $this->gw_addon_version);
     45 	}
     46 
     47 	// -------------------------------------------------------------------------------
     48 	// Initialise data items specific to this gateway
     49 	// - the account class initialises the common data items
     50 	// 
     51 	public function initData($gateway_info)
     52 	{
     53 		parent::initData($gateway_info);
     54 		$this->specific_data = new stdClass;
     55 		$this->specific_data->backend_url = '';
     56 		$this->specific_data->backend_key = '';
     57 		$this->specific_data->currency = '';
     58 		$this->specific_data->refund_time = '';
     59 		$this->specific_data->tid_optional = true;
     60 
     61 	}
     62 
     63 	// -------------------------------------------------------------------------------
     64 	// Get the post data specific to this gateway
     65 	// - the account class gets the common data items
     66 	// 
     67 	public function getPostData()
     68 	{
     69 		parent::getPostData();
     70 		$this->specific_data = new stdClass;
     71 		$jinput = JFactory::getApplication()->input;
     72 		$this->specific_data->test_mode = $jinput->get('test_mode', '0', 'STRING');
     73 		$this->specific_data->backend_url = $jinput->get('backend_url', '', 'STRING');
     74 		$this->specific_data->backend_key = $jinput->get('backend_key', '', 'STRING');
     75 		$this->specific_data->refund_time = $jinput->get('refund_time', '', 'STRING');
     76 		$currency = $this->create_payment(self::HTTP_GET, $this->specific_data->backend_url . '/config', null)['currency'];
     77 		$this->specific_data->tid_optional = true;
     78 
     79 		// To allow for custom currencies which don't use 3 Letter abbreviation
     80 		if (strlen($currency) != 3)
     81 		{
     82 			$this->specific_data->currency = $this->convertCurrency($currency, "currency2Abr");
     83 		}
     84 		else
     85 		{
     86 			$this->specific_data->currency = $currency;
     87 		}
     88 
     89 		$this->common_data->account_currency = $this->specific_data->currency;
     90 
     91 		$languages = PayageHelper::get_site_languages();
     92 
     93 		foreach ($languages as $tag => $name)
     94 		{
     95 			$this->translations[$tag]['account_language'] = $jinput->get($tag . '_account_language', '', 'string');
     96 		}
     97 
     98 		return $this->specific_data;
     99 	}
    100 
    101 	function convertCurrency($currency, $conversionType)
    102 	{
    103 		defined('JPATH_PAYMENT') or define('JPATH_PAYMENT', JPATH_SITE . '/administrator/components/com_payage');
    104 		$file = JPATH_PAYMENT . '/currencies.csv';
    105 
    106 		if (JFile::exists($file))
    107 		{
    108 			// Open the CSV file
    109 			$file = fopen($file, 'r');
    110 
    111 			while (($row = fgetcsv($file)) !== false)
    112 			{
    113 				if ($conversionType === 'currency2Abr' && $row[0] == $currency)
    114 				{
    115 					$value = $row[1];
    116 					fclose($file);
    117 					LAPG_trace::trace($value);
    118 
    119 					return $value;
    120 				}
    121 				elseif ($conversionType === 'abr2Currency' && $row[1] == $currency)
    122 				{
    123 					$value = $row[0];
    124 					fclose($file);
    125 
    126 					return $value;
    127 				}
    128 			}
    129 		}
    130 
    131 		$errors[] = JText::_('COM_PAYAGE_INVALID') . ' ' . JText::_('COM_PAYAGE_TALER_CURRENCY_NOT_FOUND');
    132 		$this->app->enqueueMessage(implode('<br />', $errors), 'error');
    133 
    134 		return 'ERR';
    135 	}
    136 
    137 	// -------------------------------------------------------------------------------
    138 	// Validate the account details
    139 	// - the account class checks the common data items
    140 	// 
    141 	public function check_post_data()
    142 	{
    143 		$errors = array();
    144 		$ok = parent::check_post_data();    // Check the common data
    145 
    146 		if (!str_starts_with($this->specific_data->backend_url, "http"))
    147 		{
    148 			$errors[] = JText::_('COM_PAYAGE_INVALID') . ' ' . JText::_('COM_PAYAGE_TALER_BACKEND_URL');
    149 		}
    150 
    151 		if (!str_starts_with($this->specific_data->backend_key, "secret-token:"))
    152 		{
    153 			$errors[] = JText::_('COM_PAYAGE_INVALID') . ' ' . JText::_('COM_PAYAGE_TALER_KEY');
    154 		}
    155 
    156 		if (!ctype_digit(trim($this->specific_data->refund_time)))
    157 		{
    158 			$errors[] = JText::_('COM_PAYAGE_INVALID') . ' ' . JText::_('COM_PAYAGE_TALER_REFUND_TIME');
    159 		}
    160 
    161 		if (!empty($errors))
    162 		{
    163 			$this->app->enqueueMessage(implode('<br />', $errors), 'error');
    164 			$ok = false;
    165 		}
    166 
    167 		return $ok;
    168 	}
    169 
    170 	// -------------------------------------------------------------------------------
    171 	// handle an incoming request from the payment gateway
    172 	// - we assume this is a genuine request because the front end found the account and payment records
    173 	// our model instance already has $this->common_data and $this->specific_data
    174 	// 
    175 	public function Gateway_handle_request($payment_model)
    176 	{
    177 
    178 		$jinput = JFactory::getApplication()->input;
    179 		$task = $jinput->get('task', '', 'STRING');
    180 		$this->payment_model = $payment_model;
    181 		$this->payment_data = $payment_model->data;
    182 
    183 		switch ($task)
    184 		{
    185 			case 'create':                        // Someone clicked a Payage Taler payment button
    186 				$action = $this->create();
    187 
    188 		return $action;
    189 
    190 			case 'return':
    191 			case 'update':
    192 			case 'refund':          // Used for the webhook
    193 				return $this->handle_return($task);
    194 
    195 			case 'cancel':
    196 				return LAPG_CALLBACK_CANCEL;
    197 
    198 			default:
    199 				LAPG_trace::trace("Taler handle_request() unknown task $task");
    200 
    201 		return LAPG_CALLBACK_BAD;            // Should never happen
    202 		}
    203 
    204 	}
    205 
    206 	// -------------------------------------------------------------------------------
    207 	// Create a payment in Taler
    208 	// - we redirect here from Taler payment buttons
    209 	// 
    210 	private function create()
    211 	{
    212 		LAPG_trace::trace('Taler create() for Payage transaction id: ' . $this->payment_data->pg_transaction_id);
    213 
    214 		$this->payment_data->account_id = $this->common_data->id;	// Save the account_id now in case of errors
    215 		$this->payment_data->gw_addon_version = $this->gw_addon_version;
    216 		$stored = $this->payment_model->store();
    217 
    218 		if (!function_exists('curl_version'))
    219 		{
    220 			LAPG_trace::trace("CURL not installed - cannot use Taler");
    221 			$this->payment_data->pg_status_code = LAPG_STATUS_FAILED;
    222 			$this->payment_data->pg_status_text = JText::_('COM_PAYAGE_CURL_NOT_INSTALLED');
    223 			$stored = $this->payment_model->store();
    224 
    225 			return LAPG_CALLBACK_USER;			// Return to the calling application
    226 		}
    227 
    228 		// Set up the payment in the gateway
    229 
    230 		$redirectUrl = htmlentities(JURI::root() . 'index.php?option=com_payage&task=return&aid=' . $this->common_data->id . '&tid=' . $this->payment_data->pg_transaction_id . '&tmpl=component&format=raw');
    231 		$customer_fee = parent::calculate_gateway_fee($this->common_data, $this->payment_data->gross_amount);
    232 		$total_amount = $this->payment_data->gross_amount + $customer_fee;
    233 		$total_amount = number_format($total_amount, 2, '.', '');	// We currently only support currencies that use two decimal places
    234 		$currency = $this->convertCurrency($this->common_data->account_currency, "abr2Currency");
    235 
    236 		if ($this->specific_data->refund_time < 10)
    237 		{
    238 			$refund_time = 0;
    239 		}
    240 		else
    241 		{
    242 			$refund_time = intval($this->specific_data->refund_time) * 1000;
    243 		}
    244 
    245 		try
    246 		{
    247 			$data = array(
    248 				'refund_delay' => array(
    249 					'd_us' => (int) $refund_time
    250 				),
    251 				'order' => array(
    252 					'amount' => $currency . ':' . $total_amount,
    253 					'summary' => Uri::getInstance()->getHost() . ' - ' . $this->payment_data->item_name,
    254 					'fulfillment_url' => $redirectUrl
    255 				)
    256 			);
    257 
    258 			// Redirect the browser to the Taler gateway
    259 
    260 			$response_data = $this->create_payment(self::HTTP_POST, $this->specific_data->backend_url . '/private/orders', json_encode($data));
    261 
    262 			$order_id = $response_data['order_id'];
    263 			$token = $response_data['token'];
    264 
    265 			// Save the payment details so far
    266 
    267 			$this->payment_data->gw_transaction_id = $order_id;
    268 			$stored = $this->payment_model->store();
    269 
    270 			$url = $this->specific_data->backend_url . '/orders/' . $order_id . '?token=' . $token;
    271 			LAPG_trace::trace("Taler redirecting to: $url");
    272 			$app = JFactory::getApplication();
    273 			$app->redirect($url);
    274 
    275 			return LAPG_CALLBACK_NONE;			// We are at the gateway - we will go back to the calling application later
    276 		}
    277 		catch (Exception $e)
    278 		{
    279 			$html = $e->getMessage() . '<br>' . JText::_('COM_PAYAGE_GATEWAY_TEST_RESPONSE_NOT_OK');
    280 			$this->app->enqueueMessage($html, 'error');
    281 
    282 			return;
    283 		}
    284 	}
    285 
    286 	private function create_payment($httpMethod, $url, $httpBody)
    287 	{
    288 		$curl = curl_init();
    289 
    290 		$headers = array(
    291 			'Authorization: Bearer ' . $this->specific_data->backend_key,
    292 			'Content-Type: application/json'
    293 		);
    294 
    295 		curl_setopt($curl, CURLOPT_URL, $url);
    296 
    297 		curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
    298 		curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
    299 		curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, self::DEFAULT_CONNECT_TIMEOUT);
    300 		curl_setopt($curl, CURLOPT_TIMEOUT, self::DEFAULT_TIMEOUT);
    301 
    302 		switch ($httpMethod)
    303 		{
    304 			case self::HTTP_POST:
    305 				curl_setopt($curl, CURLOPT_POST, true);
    306 				curl_setopt($curl, CURLOPT_POSTFIELDS, $httpBody);
    307 				break;
    308 			case self::HTTP_GET:
    309 				break;
    310 			default:
    311 				throw new InvalidArgumentException("Invalid http method: " . $httpMethod);
    312 		}
    313 
    314 		$response = curl_exec($curl);
    315 		$httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
    316 
    317 		if ($response === false)
    318 		{
    319 			$curlErrorMessage = "Curl error: " . curl_error($curl);
    320 			curl_close($curl);
    321 			throw new ErrorException($curlErrorMessage);
    322 		}
    323 
    324 		curl_close($curl);
    325 		$responseData = json_decode($response, true);
    326 		$responseData['httpCode'] = $httpCode;
    327 
    328 		return $responseData;
    329 	}
    330 
    331 	// -------------------------------------------------------------------------------
    332 	// handle a return from Taler
    333 	// - this is when Taler re-directs back to the client site after a payment
    334 	// 
    335 	private function handle_return($task)
    336 	{
    337 		LAPG_trace::trace("Taler handle_return($task) for Payage transaction id: " . $this->payment_data->pg_transaction_id);
    338 
    339 		// Used for the Webhook to get the correct Order
    340 		if ($task == 'refund')
    341 		{
    342 			if ($_SERVER['REQUEST_METHOD'] === 'POST')
    343 			{
    344 				if ($_SERVER['CONTENT_TYPE'] === 'application/json')
    345 				{
    346 					$json_data = file_get_contents('php://input');
    347 					$body = json_decode($json_data, true);
    348 
    349 					if ($body !== null)
    350 					{
    351 						$orderId = $body['order_id'];
    352 
    353 						LAPG_trace::trace('Order with Id: ' . $orderId . ' is being refunded');
    354 
    355 						$this->payment_data = $this->payment_model->getOne($orderId, 'gw_transaction_id');
    356 					}
    357 					else
    358 					{
    359 						LAPG_trace::trace("Missing Order ID in JSON body");
    360 
    361 						return LAPG_STATUS_FAILED;
    362 					}
    363 				}
    364 				else
    365 				{
    366 					LAPG_trace::trace("refunds triggered but without a JSON header");
    367 
    368 					return LAPG_STATUS_FAILED;
    369 				}
    370 			}
    371 			else
    372 			{
    373 				LAPG_trace::trace("refund triggered but wihtout a POST request");
    374 
    375 				return LAPG_STATUS_FAILED;
    376 			}
    377 		}
    378 
    379 		// Get the payment status from the gateway
    380 		$response_data = $this->create_payment(self::HTTP_GET, $this->specific_data->backend_url . '/private/orders/' . $this->payment_data->gw_transaction_id, null);
    381 		$status = $response_data['order_status'];
    382 
    383 		switch ($status)
    384 		{
    385 			case 'paid':
    386 				$new_status_code = LAPG_STATUS_SUCCESS;
    387 				break;
    388 			case 'expired':
    389 			case 'canceled':
    390 				$new_status_code = LAPG_STATUS_CANCELLED;
    391 				break;
    392 			case 'failed':
    393 				$new_status_code = LAPG_STATUS_FAILED;
    394 				break;
    395 			case 'pending':
    396 			case 'unpaid':
    397 				$new_status_code = LAPG_STATUS_PENDING;
    398 				break;
    399 			default:
    400 				$new_status_code = LAPG_STATUS_FAILED;
    401 		}
    402 
    403 		// Check for refunds
    404 
    405 		$refund_description = '';
    406 
    407 		if ($response_data['refunded'])
    408 		{
    409 			$amount_refunded = trim(explode(':', $response_data['refund_amount'])[1]);
    410 			$amount_total = trim(explode(':', $response_data['contract_terms']['amount'])[1]);
    411 			$refund_details = $response_data['refund_details'];
    412 			$refund_description = 'Taler: ' . JText::_('COM_PAYAGE_REFUNDED') . ' ' . $amount_refunded . ' details: ' . end($response_data['refund_details'])['reason'];
    413 			LAPG_trace::trace("Taler: $refund_description");
    414 			$amount_remaining = (float) $amount_total - (float) $amount_refunded;
    415 
    416 			if ($amount_remaining == 0.0)
    417 			{
    418 				$new_status_code = LAPG_STATUS_REFUNDED;
    419 				$status = 'refunded';
    420 			}
    421 		}
    422 
    423 		// Multiple calls
    424 
    425 		$result = $this->payment_model->ladb_lockTable('#__payage_payments');
    426 
    427 		if ($result === true)
    428 		{
    429 			LAPG_trace::trace('Locked the payment table ok');
    430 		}
    431 		else
    432 		{
    433 			LAPG_trace::trace('Failed to lock the payment table: ' . $this->payment_model->ladb_error_text);
    434 		}
    435 
    436 		$this->payment_data = $this->payment_model->getOne($this->payment_data->id);
    437 		$this->payment_data->account_id = $this->common_data->id;
    438 		$this->payment_data->gw_addon_version = $this->gw_addon_version;
    439 		$this->payment_data->pg_status_code = $new_status_code;
    440 		$this->payment_data->pg_status_text = $status;
    441 
    442 		// Update the history
    443 
    444 		if ($refund_description != '')
    445 		{
    446 			$this->payment_model->add_history_entry($refund_description);
    447 		}
    448 		else
    449 		{
    450 			$status_description = PayageHelper::getPaymentDescription($this->payment_data->pg_status_code);
    451 			$this->payment_model->add_history_entry("Taler: $status_description");
    452 		}
    453 
    454 		// Update the payment record
    455 		// we store some details in the root of gw_transaction_details so they are easily visible
    456 		// we also store each update separately in case something goes wrong and we need to see the full history
    457 
    458 		$stored = $this->payment_model->store();
    459 		$this->payment_model->ladb_unlock();
    460 
    461 		// For a 'return' task, we redirect to the calling application
    462 
    463 		if ($task == 'return')
    464 		{
    465 			LAPG_trace::trace("Taler $task returning LAPG_CALLBACK_USER");
    466 
    467 			return LAPG_CALLBACK_USER;
    468 		}
    469 
    470 		// It's an 'update'
    471 		// if this was a refund, we must update the application
    472 
    473 		if ($new_status_code == LAPG_STATUS_REFUNDED)
    474 		{
    475 			LAPG_trace::trace("Taler $task [refund], returning LAPG_CALLBACK_UPDATE");
    476 
    477 			return LAPG_CALLBACK_UPDATE;
    478 		}
    479 
    480 		LAPG_trace::trace("Taler $task, returning LAPG_CALLBACK_NONE");
    481 
    482 		return LAPG_CALLBACK_NONE;
    483 	}
    484 
    485 
    486 	// -------------------------------------------------------------------------------
    487 	// Verify the amount, currency and recipient of a payment
    488 	// - set the payment status code and text accordingly
    489 	// 
    490 	private function check_payment($customer_fee, $gross_received, $currency_received, $receiver_email)
    491 	{
    492 		$expected_gross = $this->payment_data->gross_amount;
    493 		$expected_total = $expected_gross + $customer_fee;
    494 		$str_expected_total = number_format($expected_total, 2);
    495 		$str_actual_total = number_format($gross_received, 2);
    496 		LAPG_trace::trace("check_payment() gross_amount = $expected_gross, customer_fee = $customer_fee, expected_payment_amount = $expected_total, gross_received = $gross_received");
    497 
    498 		if (!isset($this->specific_data->auto_tax))
    499 		{
    500 								// New parameter may not have been saved yet
    501 			$this->specific_data->auto_tax = 0;                                    // default to no
    502 		}
    503 
    504 		if (($this->specific_data->auto_tax == 0) && ($str_expected_total != $str_actual_total))
    505 		{
    506 			$this->payment_data->pg_status_code = LAPG_STATUS_FAILED;
    507 			$this->payment_data->pg_status_text = JText::sprintf("COM_PAYAGE_MISMATCH_AMOUNT", $str_expected_total, $str_actual_total);
    508 			LAPG_trace::trace($this->payment_data->pg_status_text);
    509 		}
    510 
    511 		if (($this->specific_data->auto_tax == 1) && ($str_actual_total < $str_expected_total))
    512 		{
    513 			$this->payment_data->pg_status_code = LAPG_STATUS_FAILED;
    514 			$this->payment_data->pg_status_text = JText::sprintf("COM_PAYAGE_MISMATCH_AMOUNT", $str_expected_total, $str_actual_total);
    515 			LAPG_trace::trace($this->payment_data->pg_status_text);
    516 		}
    517 
    518 		if ($this->common_data->account_currency != $currency_received)
    519 		{
    520 			$this->payment_data->pg_status_code = LAPG_STATUS_FAILED;
    521 			$this->payment_data->pg_status_text = JText::sprintf("COM_PAYAGE_MISMATCH_CURRENCY", $this->common_data->account_currency, $currency_received);
    522 			LAPG_trace::trace($this->payment_data->pg_status_text);
    523 		}
    524 
    525 		if (strcasecmp($this->common_data->account_email, $receiver_email) == 0)
    526 		{
    527 			return;
    528 		}
    529 
    530 		if (isset($this->specific_data->account_primary_email) && strcasecmp($this->specific_data->account_primary_email, $receiver_email) == 0)
    531 		{
    532 			return;
    533 		}
    534 
    535 		$this->payment_data->pg_status_code = LAPG_STATUS_FAILED;
    536 
    537 		if (isset($this->specific_data->account_primary_email))
    538 		{
    539 			$email_address = $this->common_data->account_email . ' OR ' . $this->specific_data->account_primary_email;
    540 		}
    541 		else
    542 		{
    543 			$email_address = $this->common_data->account_email;
    544 		}
    545 
    546 		$this->payment_data->pg_status_text = JText::sprintf("COM_PAYAGE_MISMATCH_RECIPIENT", $email_address, $receiver_email);
    547 		LAPG_trace::trace($this->payment_data->pg_status_text);
    548 	}
    549 
    550 
    551 	// -------------------------------------------------------------------------------
    552 	// Build a Buy Now button
    553 	// 
    554 	public function Gateway_make_button($payment_data, $call_array, $app_fee)
    555 	{
    556 
    557 		$process_url = JURI::root() . 'index.php?option=com_payage&task=create&aid=' . $this->common_data->id . '&tid=' . $payment_data->pg_transaction_id . '&tmpl=component&format=raw';
    558 		$button_url = JURI::base(true) . '/' . $this->common_data->button_image;
    559 		$html = '<form class="pb-form pb-taler" action="' . $process_url . '" method="post" >';
    560 		$html .= '<input type="image" src="' . $button_url . '" alt="Taler" title="' . $this->common_data->button_title . '" ' . $call_array['button_extra'] . '>';
    561 		$html .= "</form>";
    562 
    563 		return $html;
    564 	}
    565 
    566 	// -------------------------------------------------------------------------------
    567 	// Test a Taler API call
    568 	// 
    569 	public function Gateway_test()
    570 	{
    571 		LAPG_trace::trace("Taler gateway test with key " . $this->specific_data->backend_key);
    572 		$curl_info = curl_version();
    573 		$curl_version = $curl_info['version'];
    574 		LAPG_trace::trace("PHP version: " . PHP_VERSION);
    575 		LAPG_trace::trace("CURL version: $curl_version");
    576 		LAPG_trace::trace("Openssl version: " . OPENSSL_VERSION_TEXT);
    577 
    578 		if (!function_exists('curl_version'))
    579 		{
    580 			$this->app->enqueueMessage("FAIL: CURL is not installed", 'error');
    581 
    582 			return;
    583 		}
    584 
    585 		try                                                    // Try to connect to Taler
    586 		{
    587 			$response_data = $this->create_payment(self::HTTP_GET, $this->specific_data->backend_url . '/private', json_encode($data));
    588 			$httpCode = $response_data['httpCode'];
    589 
    590 			switch ($httpCode)
    591 			{
    592 				case 200:
    593 				case 201:
    594 					$msg = JText::_('COM_PAYAGE_GATEWAY_TEST_PASSED');
    595 					$this->app->enqueueMessage($msg, 'message');
    596 					break;
    597 				case 401:
    598 					$msg = JText::_('COM_PAYAGE_GATEWAY_TEST_BAD_KEY');
    599 					$this->app->enqueueMessage($msg, 'error');
    600 					break;
    601                 case 404:
    602                     $msg = JText::_('COM_PAYAGE_GATEWAY_TEST_BAD_URL');
    603                     $this->app->enqueueMessage($msg, 'error');
    604                     break;
    605                 case str_starts_with($httpCode, '5'):
    606                     $msg = JText::_('COM_PAYAGE_GATEWAY_TEST_SERVER_ERROR');
    607                     $this->app->enqueueMessage($msg, 'error');
    608                     break;
    609 			}
    610 		}
    611 		catch (Exception $e)
    612 		{
    613 			$html = $e->getMessage() . '<br>' . JText::_('COM_PAYAGE_GATEWAY_TEST_RESPONSE_NOT_OK');
    614 			$this->app->enqueueMessage($html, 'error');
    615 
    616 			return;
    617 		}
    618 
    619 		LAPG_trace::trace("Taler Gateway_test done");
    620 	}
    621 }
    622