Hello guys,
I just installed a new payment method but i'm having a bit of trouble with it.
The thing is that the payment gateway only supports 2 decimal places and open cart sends up to 4 decimal places so we got an error message.
My question is, is there a way to round up the value before it gets send to the gateway?
Best regards,
Levi
You will have to edit the controller of that payment method and change the total sent. Without knowing the code or the extension noone can help you. If that extension makes a total match check in its callback method, you will also have to round the order total there so it matches the total sent to the payment processor.
Here is the code for the controller.
Hope this help
Code: Select all
<?php
class ControllerPaymentMeowallet extends Controller
{
public function index()
{
$this->language->load('payment/meowallet');
$data['button_confirm'] = $this->language->get('button_confirm');
$data['action'] = $this->url->link('payment/meowallet/redirect', 'SSL');
$data['testmode'] = $this->config->get('meowallet_environment');
$data['text_testmode'] = $this->language->get('text_testmode');
return $this->load->view('default/template/payment/meowallet.tpl', $data);
}
public function redirect()
{
$this->load->model('checkout/order');
$this->load->model('payment/meowallet');
$confirm_url = $this->url->link('payment/meowallet/success');
$cancel_url = $this->url->link('checkout/checkout', '', 'SSL');
$products = $this->cart->getProducts();
$order_info = $this->model_checkout_order->getOrder($this->session->data['order_id']);
try
{
$checkout = $this->model_payment_meowallet->createCheckout($order_info, $products, $confirm_url, $cancel_url);
}
catch (\Exception $e)
{
$this->log->write($e->getMessage());
$this->response->redirect($this->url->link('payment/meowallet/error'));
}
$url = sprintf('%s%s%s=%s', $checkout->url_redirect,
false === strpos($checkout->url_redirect, '?') ? '?' : '&',
'locale', $this->getLocaleCode());
$this->response->redirect($url);
}
public function error()
{
$this->language->load('payment/meowallet');
$data['breadcrumbs'][] = array('text' => $this->language->get('text_home'),
'href' => $this->url->link('common/home'));
$data['breadcrumbs'][] = array('text' => $this->language->get('text_cart'),
'href' => $this->url->link('checkout/cart'));
$data['heading_title'] = 'MEO Wallet';
$data['text_error'] = $this->language->get('error_message');
$data['continue'] = $this->url->link('checkout/checkout', '', 'SSL');
$data['button_continue'] = $this->language->get('continue');
$data['content_bottom'] = '';
$data['header'] = $this->load->controller('common/header');
$data['column_left'] = $this->load->controller('common/column_left');
$data['column_right'] = $this->load->controller('common/column_right');
$data['footer'] = $this->load->controller('common/footer');
$this->response->setOutput($this->load->view('default/template/payment/meowallet_error.tpl', $data));
}
public function success()
{
if (isset($this->request->get['checkoutid']))
{
$id = $this->request->get['checkoutid'];
$this->load->model('payment/meowallet');
$this->model_payment_meowallet->confirmCheckout($id);
}
$this->response->redirect($this->url->link('checkout/success'));
}
public function callback()
{
$callback = $this->getRequestPayload();
try
{
$this->load->model('payment/meowallet');
$this->model_payment_meowallet->processCallback($callback);
}
catch (\InvalidArgumentException $e)
{
$this->log->write("MEOWallet received invalid callback. Request data: '$callback'");
http_response_code(400);
}
catch (\Exception $e)
{
$this->log->write('MEOWallet error processing callback. Reason: '.$e->getMessage());
http_response_code(500);
}
}
private function getRequestPayload()
{
return file_get_contents('php://input');
}
private function getLocaleCode()
{
$this->load->model('localisation/language');
$languages = $this->model_localisation_language->getLanguages();
$languageId = $this->config->get('config_language_id');
$localeCode = 'pt_PT';
foreach ($languages as $language)
{
if ($language['language_id'] == $languageId)
{
# sample data: en_US.UTF-8,en_US,en-gb,english
$_locale = explode(',', $language['locale']);
if (count($_locale) > 1)
{
$localeCode = $_locale[2];
}
break;
}
}
return $localeCode;
}
}
And here is the model file
Code: Select all
<?php
class ModelPaymentMeowallet extends Model
{
const PRODUCTION_ENVIRONMENT_ID = 0;
const PRODUCTION_SERVICE_ENDPOINT = 'https://services.wallet.pt/api/v2';
const SANDBOX_ENVIRONMENT_ID = 1;
const SANDBOX_SERVICE_ENDPOINT = 'https://services.sandbox.meowallet.pt/api/v2';
public function getMethod($address, round($total, 2, PHP_ROUND_HALF_DOWN))
{
$available = true;
$currencies = array('EUR');
$authToken = $this->getAPIToken();
if ( empty($authToken) )
{
$available = false;
}
if (false === in_array(strtoupper($this->currency->getCode()), $currencies))
{
$available = false;
}
if ($available)
{
return array(
'code' => 'meowallet',
'title' => $this->config->get('meowallet_title'),
'sort_order' => $this->config->get('meo_wallet_sort_order'),
'terms' => ''
);
}
return array();
}
public function logger($message)
{
if ($this->config->get('meowallet_debug'))
{
$log = new Log('meowallet.log');
$log->write($message);
}
}
protected function getAPIToken()
{
$environment = $this->config->get('meowallet_environment');
$key = sprintf('meowallet_%s_api_token', $environment == self::SANDBOX_ENVIRONMENT_ID ? 'sandbox' : 'production');
return $this->config->get($key);
}
protected function getServiceEndpoint($path = null)
{
$environment = $this->config->get('meowallet_environment');
$url = null;
switch ($environment)
{
case static::SANDBOX_ENVIRONMENT_ID:
$url = static::SANDBOX_SERVICE_ENDPOINT;
break;
case static::PRODUCTION_ENVIRONMENT_ID:
$url = static::PRODUCTION_SERVICE_ENDPOINT;
break;
}
if ( empty($url) )
{
throw new \UnexpectedValueException("Invalid environment configuration, set as '$environment'");
}
return sprintf('%s/%s', $url, $path);
}
public function createCheckout($order_info, $products, $url_confirm, $url_cancel)
{
$address = sprintf("%s %s", html_entity_decode($order_info['shipping_address_1'], ENT_QUOTES, 'UTF-8'),
html_entity_decode($order_info['shipping_address_2'], ENT_QUOTES, 'UTF-8'));
$client = array('name' => sprintf("%s %s", html_entity_decode($order_info['shipping_firstname'], ENT_QUOTES, 'UTF-8'),
html_entity_decode($order_info['shipping_lastname'], ENT_QUOTES, 'UTF-8')),
'email' => $order_info['email']);
$client['phone'] = $order_info['telephone'];
$client['address'] = array('country' => $order_info['shipping_iso_code_2'],
'city' => html_entity_decode($order_info['shipping_city'], ENT_QUOTES, 'UTF-8'),
'postalcode' => html_entity_decode($order_info['shipping_postcode'], ENT_QUOTES, 'UTF-8'),
'address' => trim($address));
$payment = array('client' => $client,
'amount' => $order_info['total'],
'currency' => $order_info['currency_code'],
'items' => array(),
'ext_invoiceid' => $order_info['order_id']);
foreach ($products as $product)
{
$payment['items'][] = array('ref' => $product['product_id'],
'name' => $product['name'],
'descr' => $product['name'],
'qt' => $product['quantity']);
}
$request_data = json_encode(array('payment' => $payment,
'url_confirm' => $url_confirm,
'url_cancel' => $url_cancel));
$authToken = $this->getAPIToken();
$headers = array(
'Authorization: WalletPT ' . $authToken,
'Content-Type: application/json',
'Content-Length: ' . strlen($request_data)
);
$ch = curl_init();
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
curl_setopt($ch, CURLOPT_URL, $this->getServiceEndpoint('checkout'));
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_POSTFIELDS, $request_data);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
$response = json_decode( curl_exec($ch) );
if (curl_errno($ch))
{
$message = sprintf('MEOWallet Could not create procheckout. Reason: %s', curl_error($ch));
throw new \Exception($message);
}
if ( false == is_object($response)
|| false == property_exists($response, 'id')
|| false == property_exists($response, 'url_redirect')
)
{
$response_data = var_export($response);
$message = sprintf('MEOWallet Could not create procheckout. Service response: %s', $response_data);
throw new \Exception($message);
}
$this->db->query(sprintf("INSERT INTO `" . DB_PREFIX . "meowallet_order` VALUES (%d, '%s')",
(int) $this->db->escape($order_info['order_id']), $this->db->escape($response->id)));
return $response;
}
public function processCallback($verbatim_callback)
{
if (false === $this->isValidCallback($verbatim_callback))
{
throw new \InvalidArgumentException('Invalid callback');
}
$callback = json_decode($verbatim_callback);
$this->logger(sprintf("MEOWallet callback for invoice_id '%s' with status '%s'",
$callback->ext_invoiceid, $callback->operation_status));
try
{
$this->processPayment($callback->operation_id,
$callback->ext_invoiceid,
$callback->operation_status,
$callback->amount,
$callback->method);
}
catch (\Exception $e)
{
throw $e;
}
}
public function confirmCheckout($checkout_id)
{
$order_id = $this->getCheckoutOrderId($checkout_id);
if ( null == $order_id )
{
throw new \InvalidArgumentException("MEOWallet no checkout '$checkout_id' found!");
}
$this->load->model('checkout/order');
$order_info = $this->model_checkout_order->getOrder($order_id);
if ( ! $order_info )
{
throw new \InvalidArgumentException("MEOWallet no order with id '$order_id' found!");
}
if ( ! $order_info['order_status_id'] )
{
$order_status = $this->config->get('meowallet_pending_order_status_id');
$this->model_checkout_order->addOrderHistory($order_info, $order_status, "MEOWallet transaction id $checkout_id", true);
}
}
private function isValidCallback($data)
{
$authToken = $this->getAPIToken();
$headers = array(
'Authorization: WalletPT ' . $authToken,
'Content-Type: application/json',
'Content-Length: ' . strlen($data));
$ch = curl_init();
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
curl_setopt($ch, CURLOPT_URL, $this->getServiceEndpoint('callback/verify'));
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
$response = curl_exec($ch);
if (0 == strcasecmp('true', $response))
{
return true;
}
if (0 != strcasecmp('false', $response))
{
throw new \InvalidArgumentException("MEOWallet callback validation returned unexpected response '$response'");
}
return false;
}
private function processPayment($transaction_id, $order_id, $status, $amount, $method)
{
$this->logger(sprintf("Processing payment for transaction_id: '%s' order_id '%s' with status '%s', amount '%s'",
$transaction_id, $order_id, $status, $amount));
$this->load->model('checkout/order');
$order_info = $this->model_checkout_order->getOrder($order_id);
if ( ! $order_info )
{
throw new \InvalidArgumentException("MEOWallet no order with id '$order_id' found!");
}
switch ($status)
{
case 'COMPLETED':
$is_partial_payment = ((float)$amount != $this->currency->format($order_info['total'],
$order_info['currency_code'],
$order_info['currency_value'],
false));
if ($is_partial_payment)
{
throw new \InvalidArgumentException('MEOWallet amount paid mismatch order value');
}
$orderStatus = $this->config->get('meowallet_completed_order_status_id');
break;
case 'FAIL':
/**
* If transaction fails and it wasn't previously marked as pending, there is no need to inform user or the merchant.
* Since the user will be redirected to checkout page to retry the payment.
*/
$orderStatus = null;
if ( $order_info['order_status_id'] )
{
$orderStatus = $this->config->get('meowallet_failed_order_status_id');
}
break;
case 'NEW':
case 'PENDING':
$orderStatus = $this->config->get('meowallet_pending_order_status_id');
break;
default:
throw new \InvalidArgumentException("MEOWallet payment operation status '$status' not handled by this module!");
}
$comment = "MEO Wallet payment status is $status. Checkout ID: $transaction_id Method: $method";
$this->model_checkout_order->addOrderHistory($order_info['order_id'], $orderStatus, $comment);
}
private function getCheckoutOrderId($checkout_id)
{
$qry = $this->db->query("SELECT order_id FROM `" . DB_PREFIX . "meowallet_order`
WHERE `meowallet_checkout_id` = '" . $this->db->escape($checkout_id) . "' LIMIT 1");
$orderId = null;
if ( $qry->num_rows )
{
$orderId = $qry->row['order_id'];
}
return $orderId;
}
}
In the model change
to
Code: Select all
$order_info['total']
Code: Select all
round($order_info['total'], 2)
Who is online
Users browsing this forum: No registered users and 54 guests