One of the big new features brought by MS Core is the ability to use multiple payment gateways, instead of just PayPal. There are literally hundreds of payment gateways out there, so in this tutorial we will be demonstrating how to make a payment gateway that will work with the MS Core system.
The first thing you have to determine is what kinds of payments your gateway can support. There are two types of payments: Cart (single payments) or Recurring (multiple payments for one order, over time). Some gateways can support both types of payments, such as PayPal WPS, AlertPay and Authorize.net. But most gateways only offer single payment support.
The first thing you need to do with your gateway is create a hook_menu function to register at least two paths: your checkout page and your settings page.
/**
* Implementation of hook_menu
*/
function mygateway_menu() {
$items = array();
$items['ms/checkout/mygateway'] = array(
'title' => 'Checkout',
'page callback' => 'mygateway_checkout',
'access callback' => 'mygateway_access_test',
'type' => MENU_CALLBACK,
);
$items['admin/moneyscripts/gateways/mygateway'] = array(
'title' => 'MyGateway',
'description' => 'Set the various MyGateway Settings here',
'page callback' => 'drupal_get_form',
'page arguments' => array('mygateway_admin'),
'access arguments' => array('administer moneyscripts settings'),
'type' => MENU_NORMAL_ITEM,
);
return $items;
}
Next, we need to register the gateway with MS Core using hook_ms_payment_gateway:
/**
* Implementation of hook_ms_payment_gateway
*
* This is the function you will use to register your gateway with MS Core
* You will need to give a name and a description and a module for the gateway
* You will also need to give a path for the checkout page (where the checkout form will be shown)
* If your gateway supports cancelling recurring memberships, you can provide a function to generate the cancel link for the users
* If the gateway support recurring payments, then mark it as TRUE, otherwise set it as FALSE
* Same thing goes for cart payments
*/
function mygateway_ms_payment_gateway() {
$gateway[] = array(
'name' => 'MyGateway',
'description' => 'Pay with a Credit Card',
'module' => 'mygateway',
'path' => 'ms/checkout/mygateway',
'cancel_url' => '',
'modify_url' => '',
'recurring' => TRUE,
'cart' => TRUE,
'active' => TRUE,
);
return $gateway;
}
Next, we will need to create an admin settings form. For this example, we are going to give two settings, a Login ID and Transaction Key:
/**
* Admin Settings Form
*/
function mygateway_admin() {
$form['api_creds'] = array(
'#type' => 'fieldset',
'#title' => t('API Credentials'),
);
$form['api_creds']['mygateway_api_login_id'] = array(
'#type' => 'textfield',
'#title' => t('API Login ID'),
'#default_value' => variable_get('mygateway_api_login_id', ''),
'#description' => t('Example field to collect a login id'),
);
$form['api_creds']['mygateway_api_transaction_key'] = array(
'#type' => 'textfield',
'#title' => t('Transaction Key'),
'#default_value' => variable_get('mygateway_api_transaction_key', ''),
'#description' => t('Example field to collect a transaction key'),
);
return system_settings_form($form);
}
Next step is to create a checkout form for the user to enter their credit card info:
/*
* Make a form to show on the checkout page, to collect the CC and Address Info
*/
function mygateway_checkout() {
// Get the Form
return drupal_get_form('mygateway_checkout_form');
}
/*
* Build the Checkout Form
*/
function mygateway_checkout_form($form_state) {
// Load the basic credit card form from MS Core
ms_core_get_cc_form($form);
// Load the basic billing address form from MS Core
ms_core_get_billing_form($form);
// Get the $order from the session
if (!$order = ms_core_load_session_order()) {
// Error
return t('The order could not be loaded from the session');
}
// Store the order id for later
$form['ms_oid'] = array(
'#type' => 'value',
'#value' => $order->oid,
);
// Add the submit button
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Pay Now'),
);
return $form;
}
The form generated will look like this:
The form validation function is where we will attempt to validate and charge the card:
/*
* Validate the Checkout Form, and Try to Charge the Card
*/
function mygateway_checkout_form_validate($form, &$form_state) {
$form_values = $form_state['values'];
// Load the order
$order = ms_core_order_load($form_values['ms_oid']);
switch ($order->order_type) {
case 'recurring':
$response = mygateway_charge_recurring($order, $form_values, $order->recurring_schedule);
if ($response['approved'] == TRUE) {
// The credit card was approved, reset the order id and that the order was charged successfully
$form_state['values']['ms_oid'] = $order->oid;
$form_state['values']['ms_order_charged'] = TRUE;
// Insert the Payment to the database
$payment = ms_core_new_payment($order->oid, 'mygateway', 'rec_signup');
// It is important to make the first payment recorded be of type rec_signup
$payment->transaction = $response['data']['transaction'];
$payment->amount = $response['data']['amount'];
$payment->currency = $response['data']['currency'];
$payment->data = $response['data'];
$payment->recurring_schedule = $order->recurring_schedule;
// Update the address
$payment->billing_address = array(
'street' => $form_values['billing_address1'] .'\n'. $form_values['billing_address2'],
'city' => $form_values['billing_city'],
'state' => $form_values['billing_state'],
'zip' => $form_values['billing_zip'],
'country' => $form_values['billing_country'],
'phone' => $form_values['billing_phone'],
);
$payment->shipping_address = $payment->billing_address;
// Add the Payment to the Order
ms_core_enter_payment($payment, FALSE);
}
else { // The Credit Card was not approved, set an error on the form
form_set_error('ccnumber', t('Error') .': '. $response['message']);
}
break;
case 'cart':
$response = mygateway_charge_single($order, $form_values);
if ($response['approved'] == TRUE) {
// The credit card was approved
$form_state['values']['ms_oid'] = $order->oid;
$form_state['values']['ms_order_charged'] = TRUE;
// Insert the Payment to the database
$payment = ms_core_new_payment($order->oid, 'mygateway', 'cart');
$payment->transaction = $response['data']['transaction'];
$payment->amount = $response['data']['amount'];
$payment->currency = $response['data']['currency'];
$payment->data = $response['data'];
$payment->recurring_schedule = array();
// Update the address
$payment->billing_address = array(
'street' => $form_values['billing_address1'] .'\n'. $form_values['billing_address2'],
'city' => $form_values['billing_city'],
'state' => $form_values['billing_state'],
'zip' => $form_values['billing_zip'],
'country' => $form_values['billing_country'],
'phone' => $form_values['billing_phone'],
);
$payment->shipping_address = $payment->billing_address;
// Add the Payment to the Order
ms_core_enter_payment($payment);
}
else { // The Credit Card was not approved, set an error on the form
form_set_error('ccnumber', t('Error') .': '. $response['message']);
}
break;
}
}
As you can see, we first check what kind of order this is, recurring or cart, and process the payments accordingly. If it is successful, we enter the payment into the MS Core system, otherwise, we report what error prevented the payment from going through.
The submit function is where we redirect the user to the thankyou page and mark the order as completed:
/*
* The card has been charged, mark the order as completed
*/
function mygateway_checkout_form_submit($form, &$form_state) {
$v = $form_state['values'];
// If the Order was charged, complete it
if ($v['ms_order_charged']) {
$order = ms_core_order_load($v['ms_oid']);
$order->status = 'Completed';
$order = ms_core_order_save($order);
drupal_goto('ms/thankyou');
}
else {
// There was an error...
}
}
I am also attaching the example module files below for you to look at. I've tried to comment the code to explain what is going on. The code also illustrates how to use the Product Override system, allowing your products to override default gateway settings on a per-product basis. I hope you enjoyed the tutorial and if you have any questions, feel free to comment below :)
Sincerely,
Leighton Whiting
| Attachment | Size |
|---|---|
| mygateway.zip | 3.88 KB |








Comments
drupal 7 example
can you please upload a drupal 7 gateway example?
even just the zip file will be good.
Thanks!
I just updated the attached
I just updated the attached file to use the new product overrides system, along with other changes. It is still for Drupal 6, but it should be similar or exactly the same on Drupal 7. Maybe some small changes to the form function, but not much.
If you are going to be making a payment gateway module, it is always suggested to start from an existing payment gateway module like ms_paypal_wps. This example file is mostly just to illustrate how the hooks work.
Sincerely,
Leighton Whiting
Paypal website payments pro
Have you or anyone else created this module for Paypal website payments pro alrady. Is This a way we could use our existing account and members can subscribe without leaving our website to go to paypal website?
I was hoping to be able to do this without needing to edit all the code you have provided above?
Any ideas welcome
PayPal WPP would allow for
PayPal WPP would allow for the functionality you described, but it isn't completed yet. I have it on my list of things to do, but need to get some other things done first. If you are simply looking for a good solution that allows users to stay on your site, I suggest the already fully functional Authorize.net with CIM, which allows for easy and seamless Upgrading and Downgrading, as well as Recurring Payments. The users only have to enter their payment info once and can then re-use that info for future purchases on your site.
Sincerely,
Leighton Whiting
PayPal WPP is done
Just wanted to note that PayPal WPP now has a payment gateway that is supported by MS Core.
US only?
From a quick look at the authorize.net website it looks like, unlike ppwpp, it is a US only solution. Does anyone know otherwise?