Skip to main content

For a recently launched Bluespark project that uses Drupal Commerce to support the sale to tickets to events we needed to implement a new payment method as no solution was readily available.

Drupal Commerce not only makes this possible, but it enables it in a way that makes good use of standard Drupal APIs, concepts and it plugs nicely into Rules, which Drupal Commerce uses extensively.

Declaring your custom Payment method

One of the pieces in Drupal Commerce that uses Rules to work is thePayment methods. When you create a new Payment method it must be declared through hook_commerce_payment_method_info():

 function commerce_paypal_ec_commerce_payment_method_info() {
   $payment_methods['paypal_ec'] = array(
     'base' => 'commerce_paypal_ec',
     'title' => t('PayPal EC'),
     'short_title' => t('PayPal'),
     'display_title' => t('This could be a rich HTML format description displayed in the radio select list of payment methods.'),
     'description' => t('PayPal Express Checkout'),
     'terminal' => FALSE,
     'offsite' => TRUE,
     'offsite_autoredirect' => TRUE,
   );
   return $payment_methods;
 }

After declaring your payment method it will be available through Payment Rules on admin/commerce/config/payment-methods that consist of three components:

  1. EVENT: Indicates that event that will activate the rule. In the case of a Payment Rule this will always react on "Select available payment methods for an order" event. This is when a user gets to the checkout page that displays the available payment methods for an order.

  2. CONDITION: Indicates what conditions if any must hold true when the event fires. A good example would be that a particular Payment method is available only when shipping to a certain country or the order total is greater than a given quantity.

  3. ACTION: For each payment method you will have the "enable payment method action". The action has an option to edit some configurations that your payment method can provide through a settings form callback.

Making your new Payment method configurable

Once you declared your payment method it will help the long-term maintenance and use of your payment method if you make all the parameters configurable. This is straighforward through the Commerce Payment API since we have the paymenthmethod_settings_form() callback that is integrated with the payment method action Rule. This callback must return a form array that uses the Drupal form API and all the settings values are processed automatically without creating a custom submit function:

 /**
   * Payment method callback: settings form.
   */
 function commerce_paypal_ec_settings_form($settings = NULL) {
    $form = array();

    // this create a configuration for a username to connect Paypal API
    $form['api_username'] = array(
      '#type' => 'textfield',
      '#title' => t('PayPal API Username'),
      '#description' => t('The PayPal API Username.'),
      '#default_value' => $settings['api_username'],
      '#required' => TRUE,
    );
    // could have many configuration parameters in this form
 }

All these settings will be passed to the other Payment callbacks making it easy to implement the form that processes the payments.

Processing your new Payment method

There are two ways to process a payment once it has been included in the list of available payment methods:

Process the payment in the Drupal side: This is useful for processing payments via a web service where all the credit card data is captured on site and not required to redirect the user to another server. For this case, you will create a form to capture the information and a submit function that processes the transaction, using the callbacks:

  1. CALLBACK_commerce_payment_method_submit_form(). Allows for declaring a form array using the form API elements to capture payment data.

  2. CALLBACK_commerce_payment_method_submit_form_validate(). Validate function triggered when a user submits the capture payment data form. This is where you can validate payment data and raise error messages to alert the user of missing or erroneous data.

  3. CALLBACK_commerce_payment_method_submit_form_submit(). Submit function responsible for executing the transaction, it is supposed to connect to the bank service to process the transaction using the captured payment data.

  4. Process the payment externally, a good example of this is the basic Paypal flow where the user is redirected to Paypal to capture payment data. Once the payment is processed the user is redirected again to your application:

    1. CALLBACK_commerce_payment_method_redirect_form(). You provide a form array using the form API that the main goal is to redirect the user to the external page where the payment is processed. This form will be automatically submitted when the user comes to the payment redirect form, the page that will be used for the redirection is the URL specified in the $form['#action'] where you can define an external service. E.g. In the case of Paypal Exptress Checkout this URL will be https://www.paypal.com/webscr&cmd=_express-checkout&token=thetokenid

    2. CALLBACK_commerce_payment_method_redirect_form_validate(). Almost all the external services that process a payment require a return URL that will be used to redirect the user to your application after payment completion. In this case a special URL will be generated using the $order->data['payment_redirect_key'] parameter. This unique key allows Drupal Commerce to invoke the validate and submit function that corresponds to your form redirect. So as a normal form function here you can process validations for a payment transaction.

    3. CALLBACK_commerce_payment_method_redirect_form_submit(). Finally in the submit callback you can capture the transaction and process any internal workflow for the processed payment.

    Useful functions

    Here is a list of some other useful functions that you may end using.

    commerce_payment_redirect_pane_previous_page($order); In case of a failed payment transaction, calling this function redirects the user to the previous page.

    commerce_payment_redirect_pane_next_page($order); Determines the next checkout page and redirects to it in case the payment transaction was successful.

    commerce_payment_transaction_load_multiple($transaction_ids = array(), $conditions = array(), $reset = FALSE); Gets a transaction looking by specific key, in this example by 'remote_id'.

    commerce_payment_transaction_new($method_id = '', $order_id = 0); Initializes a payment transaction object for a specific order.

    commerce_payment_transaction_save($transaction); Saves the new transaction info in DB.

    commerce_currency_decimal_to_amount($decimal, $currency_code, $round = TRUE); Converts a decimal price to the integer format used to store in DB.

    commerce_currency_amount_to_decimal($amount, $currency_code); Converts the integer amount to decimal format depending on the currency config.

    commerce_tax_total_amount($components, $included, $currency_code); Having a price components array this calculates the total only for tax components.

    commerce_tax_components($components); Retrieves from price components array only the tax elements.

Please Share

-
Drupal Engineer
Born and raised in Mexico City, Pablo Cerda now lives with his wife and sons on the Mediterranean coast in south-eastern Spain. 

We'd love to partner with you on your next project!

Since we’re big on relationships, we’re all about finding the right fit. Will you take the next step with us to see if we’re a match?

3 Comments

Camilo (not verified) - Tue, Sep 3, 2013 at 5:10 pm Permalink

Camilo (not verified) - Mon, Feb 10, 2014 at 10:25 pm Permalink

Heitor (not verified) - Tue, Feb 18, 2014 at 1:42 pm Permalink

Add new comment