Skip to content

Commit

Permalink
Version 1.0.3
Browse files Browse the repository at this point in the history
+ Solves double-clicking a Mollie payment method would produce an error. Fix by creating orders in webhook.
+ Which also solves that cancelling a Mollie payment would return customers to an empty cart.
+ Solves google analytics problems by using the built-in success page.
  • Loading branch information
Bastiaan Peters committed Sep 8, 2014
1 parent 604980e commit f7e2ae6
Show file tree
Hide file tree
Showing 12 changed files with 237 additions and 147 deletions.
38 changes: 9 additions & 29 deletions mollie/controllers/front/payment.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@ class MolliePaymentModuleFrontController extends ModuleFrontController
public function initContent()
{
parent::initContent();

/** @var Cart $cart */
$cart = $this->context->cart;
$customer = new Customer($cart->id_customer);
Expand Down Expand Up @@ -99,30 +98,16 @@ public function initContent()
$orig_amount = $cart->getOrderTotal(TRUE, Cart::BOTH);
$amount = $this->_convertCurrencyToEuro($orig_amount);

// Validate
$this->module->validateOrder(
(int) $cart->id,
/* Set initial status to the status selected in the admin, in case of custom status definitions */
$this->module->statuses[Mollie_API_Object_Payment::STATUS_OPEN],
$orig_amount,
$method,
NULL,
array(),
NULL,
FALSE,
$customer->secure_key
);

// Prepare payment
$order_id = $this->module->currentOrder;
$payment_data = $this->_getPaymentData($amount, $method, $issuer, $order_id);
$payment_data = $this->_getPaymentData($amount, $method, $issuer, (int) $cart->id);
$payment = $this->_createPayment($payment_data);

// Store payment

// Store payment linked to cart
Db::getInstance()->insert(
'mollie_payments',
array(
'order_id' => $order_id,
'cart_id' => (int) $cart->id,
'method' => $payment->method,
'transaction_id' => $payment->id,
'bank_status' => Mollie_API_Object_Payment::STATUS_OPEN,
Expand Down Expand Up @@ -247,24 +232,19 @@ protected function _convertCurrencyToEuro($amount)
* @param float $amount
* @param string $method
* @param string|null $issuer
* @param int $order_id
* @param int $cart_id
* @return array
*/
protected function _getPaymentData($amount, $method, $issuer, $order_id)
protected function _getPaymentData($amount, $method, $issuer, $cart_id)
{
$payment_data = array(
"amount" => $amount,
"method" => $method,
"issuer" => $issuer,
"description" => str_replace('%', $order_id, $this->module->getConfigValue('MOLLIE_DESCRIPTION')),
"redirectUrl" => $this->context->link->getModuleLink('mollie','return', array(
'id' => $order_id,
'ref' => Order::getUniqReferenceOf($order_id))
),
"description" => str_replace('%', '', $this->module->getConfigValue('MOLLIE_DESCRIPTION')),
"redirectUrl" => $this->context->link->getModuleLink('mollie','return', array('cart_id' => $cart_id)),
"webhookUrl" => $this->context->link->getModuleLink('mollie', 'webhook'),
"metadata" => array(
"order_id" => $order_id,
),
"metadata" => array("cart_id" => $cart_id)
);

if (isset($this->context, $this->context->cart))
Expand Down
46 changes: 33 additions & 13 deletions mollie/controllers/front/return.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,22 +53,38 @@ class MollieReturnModuleFrontController extends ModuleFrontController
public function initContent()
{
parent::initContent();
$data = array();
/**
* Set ref is indicative of a payment that is tied to an order instead of a cart, which
* we still support for transitional reasons.
*/
if (isset($_GET['ref']))
{
$order_id = (int) $_GET['id'];

$order_id = (int) $_GET['id'];
// Check if user is allowed to be on the return page
$data['auth'] = Order::getUniqReferenceOf($order_id) === $_GET['ref'];
if ($data['auth'])
{
$data['mollie_info'] = $this->module->getPaymentBy('order_id', (int)$order_id);
}
}
elseif (isset($_GET['cart_id']))
{
$cart_id = (int) $_GET['cart_id'];

// Check if user is allowed to be on the return page
$data['auth'] = Order::getUniqReferenceOf($order_id) === $_GET['ref'];
// Check if user that's seeing this is the cart-owner
$cart = new Cart($cart_id);
$data['auth'] = (int)$cart->id_customer === $this->context->customer->id;
if ($data['auth'])
{
$data['mollie_info'] = $this->module->getPaymentBy('cart_id', (int)$cart_id);
}
}

// Get order information (if user is allowed to see it)
if ($data['auth'])
if (isset($data['auth']) && $data['auth'])
{
$data['mollie_info'] = Db::getInstance()->getRow(
sprintf(
'SELECT * FROM `%s` WHERE `order_id` = %d',
_DB_PREFIX_ . 'mollie_payments',
$order_id
)
);
// any paid payments for this cart?
if ($data['mollie_info'] === FALSE)
{
Expand All @@ -83,12 +99,16 @@ public function initContent()
$data['msg_details'] = $this->module->lang('We have not received a definite payment status. You will be notified as soon as we receive a confirmation of the bank/merchant.');
break;
case Mollie_API_Object_Payment::STATUS_CANCELLED:
$data['msg_details'] = $this->module->lang('You have cancelled your order.');
Tools::redirect('/index.php?controller=order&step=3');
break;
case Mollie_API_Object_Payment::STATUS_EXPIRED:
$data['msg_details'] = $this->module->lang('Unfortunately your order was expired.');
break;
case Mollie_API_Object_Payment::STATUS_PAID:
if(isset($cart_id))
{
Tools::redirectLink(__PS_BASE_URI__ . 'index.php?controller=order-confirmation&id_cart=' . $cart_id .'&id_module='. $this->module->id .'&id_order=' . Order::getOrderByCartId(intval($cart_id)) . '&key=' . $this->context->customer->secure_key);
}
$data['msg_details'] = $this->module->lang('Thank you. Your order has been received.');
break;
default:
Expand Down
60 changes: 45 additions & 15 deletions mollie/controllers/front/webhook.php
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,9 @@ protected function _executeWebhook()
return 'OK';
}

$id = Tools::getValue('id');
$transaction_id = Tools::getValue('id');

if (empty($id))
if (empty($transaction_id))
{
if ($this->module->getConfigValue('MOLLIE_DEBUG_LOG') == Mollie::DEBUG_LOG_ERRORS)
{
Expand All @@ -86,36 +86,66 @@ protected function _executeWebhook()

try
{
/** @var Mollie_API_Object_Payment $payment */
$payment = $this->module->api->payments->get($id);
$order_id = $payment->metadata->order_id;
$status = $payment->status;
/** @var Mollie_API_Object_Payment $api_payment */
$api_payment = $this->module->api->payments->get($transaction_id);
$transaction_id = $api_payment->id;
}
catch (Exception $e)
{
if ($this->module->getConfigValue('MOLLIE_DEBUG_LOG') == Mollie::DEBUG_LOG_ERRORS)
{
Logger::addLog(__METHOD__ . 'said: Could not retrieve payment details for id "' . $id . '". Reason: ' . $e->getMessage(), Mollie::WARNING);
Logger::addLog(__METHOD__ . 'said: Could not retrieve payment details for transaction_id "' . $transaction_id . '". Reason: ' . $e->getMessage(), Mollie::WARNING);
}
return 'NOT OK';
}

$ps_payment = $this->module->getPaymentBy('transaction_id', $transaction_id);

if (isset($api_payment->metadata->cart_id))
{
if (
$ps_payment['bank_status'] === Mollie_API_Object_Payment::STATUS_OPEN &&
$api_payment->status === Mollie_API_Object_Payment::STATUS_PAID )
{
// Misnomer ahead: think of validateOrder as "createOrderFromCart"
$this->module->validateOrder(
(int) $api_payment->metadata->cart_id,
$this->module->statuses[$api_payment->status],
$api_payment->amount,
$api_payment->method
);

$order_id = $this->module->currentOrder;
}
}

/**
* Older versions tie payments to orders, and create a cart upon payment creation.
* In order to support the transition between these two cases we check for the
* occurrence of order_id in the metadata. In these cases we only update the order status
*/

elseif (isset($api_payment->metadata->order_id))
{

$order_id = $api_payment->metadata->order_id;

$this->module->setOrderStatus($order_id, $api_payment->status);
}

// Store status in database
if (!$this->_saveOrderStatus($order_id, $status))
if (!$this->_savePaymentStatus($transaction_id, $api_payment->status))
{
if ($this->module->getConfigValue('MOLLIE_DEBUG_LOG') == Mollie::DEBUG_LOG_ERRORS)
{
Logger::addLog(__METHOD__ . 'said: Could not save order status for payment "' . $id . '". Reason: ' . Db::getInstance()->getMsgError(), Mollie::WARNING);
Logger::addLog(__METHOD__ . 'said: Could not save Mollie payment status for transaction "' . $transaction_id . '". Reason: ' . Db::getInstance()->getMsgError(), Mollie::WARNING);
}
}

// Tell status to Shop
$this->module->setOrderStatus($order_id, $status);

// Log successful webhook requests in extended log mode only
if ($this->module->getConfigValue('MOLLIE_DEBUG_LOG') == Mollie::DEBUG_LOG_ALL)
{
Logger::addLog(__METHOD__ . 'said: Received webhook request for order ' . (int) $order_id . ' / transaction ' . htmlentities($id), Mollie::NOTICE);
Logger::addLog(__METHOD__ . 'said: Received webhook request for order ' . (int) $order_id . ' / transaction ' . $transaction_id, Mollie::NOTICE);
}
return 'OK';
}
Expand All @@ -126,13 +156,13 @@ protected function _executeWebhook()
* @param $status
* @return bool
*/
protected function _saveOrderStatus($order_id, $status)
protected function _savePaymentStatus($transaction_id, $status)
{
$data = array(
'updated_at' => date("Y-m-d H:i:s"),
'bank_status' => $status,
);

return Db::getInstance()->update('mollie_payments', $data, '`order_id` = ' . (int)$order_id);
return Db::getInstance()->update('mollie_payments', $data, '`transaction_id` = \'' . Db::getInstance()->escape($transaction_id) . '\'');
}
}
Loading

0 comments on commit f7e2ae6

Please sign in to comment.