I'm implementing a payment gateway module which works fine as long the authorization is successful.
To route the callback from the credit card company I've set-up a success and a failure link as described in http://drupal.org/node/1040318.
url('checkout/' . $order->order_id . '/payment/return/' . $order->data['payment_redirect_key'], array('absolute' => TRUE))
url('checkout/' . $order->order_id . '/payment/back/' . $order->data['payment_redirect_key'], array('absolute' => TRUE))
If an authorization is accepted it redirects to
CALLBACK_commerce_payment_method_redirect_form_validate
CALLBACK_commerce_payment_method_redirect_form_submit
There I create a new transaction, store it and the checkout process is finished by commerce.
However if the authorization fails, non of the callbacks described in commerce_payment.api.php is called. The user is silently redirected back to the checkout page.
How can I do custom processing when the failure back link is called from the credit card company? I want to show the error message from the credit card company to the user.
For now I found this solution. But I don't think that it's really the intention doing it that way:
I implemented hook_commerce_checkout_router to get a hand on the data sent from the credit card company, store it in the $_SESSION variable and check in CALLBACK_commerce_payment_method_submit_form whether there's something stored in $_SESSION.
This is my code:
function commerce_datatrans_commerce_checkout_router($order, $checkout_page) {
// check whether this is a failed payment atempt
$data = $_POST;
if (isset($data) && isset($data['status']) && $data['status']=='error' && arg(3)=='back' && arg(4)==$order->data['payment_redirect_key']) {
$_SESSION['commerce_datatrans_error'] = $data;
//_commerce_datatrans_transaction_save($payment_method, $order, $data, COMMERCE_PAYMENT_STATUS_FAILURE);
}
}
function commerce_datatrans_submit_form($payment_method, $pane_values, $checkout_pane, $order) {
$data = isset($_SESSION['commerce_datatrans_error']) ? $_SESSION['commerce_datatrans_error'] : NULL ;
if (isset($data)) {
drupal_set_message(_commerce_datatrans_map_error_code($data['errorCode']), 'error');
unset($_SESSION['commerce_datatrans_error']);
}
return array();
}
How should this be implemented in a clean way?
Comments
Comment #1
rszrama commentedThe solution here if I'm reading you right is to not use the "Back" url for cancellations. The "Back" url is to be used for a customer initiated cancellation, not one due to failed payment. For that, just send them to the "Return" url and add the logic to the validate handler to check the payment info, display the message, and redirect the user to the previous page (using commerce_payment_redirect_pane_previous_page() and drupal_goto()).
You can view the code in Commerce PayPal WPS for an example of this in action.
Comment #2
pluess commentedThanks a lot for the fast answer!
Yes, that makes perfect sense.
Comment #3
rszrama commentedExcellent, happy to help. : )
Comment #4
pluess commentedJus for the record.
It seams to be enough to return TRUE or FALSE in CALLBACK_commerce_payment_method_redirect_form_validate(). There was no need to explicitly call commerce_payment_redirect_pane_previous_page(). Actually this is what is written in the API docs of the callback return value.
Comment #5
rszrama commentedHah, you're right. My apologies. Return FALSE basically does what I advised you to do, but I was confusing it with the IPN process. : P