Ubercart as a donation system + Moneris as a Payment Gateway



July 16, 2010

Hopefully this blog entry will help a few people overcome some of the hurdles in setting up a donations system. We are a drupal shop so all the following is for drupal 6.

In this case the client simply wanted to have a way to collect donations from supporters of their political campaign. The only real constraint was that it needed to integrate with the Moneris payment gateway system. I was looking at creating a custom donation system and integration to Moneris, but in the end opted to use Ubercart. Ubercart is an awesome beast of a Shopping cart system that has many great features and useful contribs, 90% of which I did not need to take advantage of. However, Ubercart, in an extremely stripped down form, looked like it could offer everything I needed in terms of accepting and tracking donations. There was also an existing UC Moneris contrib module that looked pretty simple.

What you will find in this blog



Modules you can use to set up a donations system

  1. Ubercart + optional sub-modules
    • uc-core(optional): Reports
    • uc-payments:Test Gateway
  2. Ubercart Donation Products
  3. Moneris Payment Gateway for Ubercart
  4. CSS Injector

Depending on how you serve drupal sites will determine where you should place the Ubercart modules. The site I was working on was on a multi-site install where different clients have user accounts for their respective sites. For this reason I installed Ubercart under the sites/{sitename}/modules directory. An install of Ubercart already existed in sites/all/modules which I could have easily used. However, to change the email templates, Ubercart requires that they reside in its .../ubercart/uc_orders/templates directory. So for the sake of this site's privacy I installed it locally so that no other site could be configured to use the same email templates.

It doesn't matter where you install the other modules.

Simpley enable the 'ubercart donation products', 'css injector', 'moneris Payment gateway for ubercart' - or other payment gateways you will be using, 'test gateway' and 'reports' modules. By default Drupal will want to enable the rest of the Ubercart module/functionality that you need. Doing it this way will enable the minimum set of modules you will need for your donation system.

BTW - There is also a donations page module that comes with 'ubercart donation products' that you can enable to display a page of all your donations. I only had the one so it wasn't needed.


Initial Setup and Configurations to disguise Ubercart Orders as donations

The following are helpful examples of the settings I used.

Donation Product Settings

There is now a new 'Donation' content type courtesy of the 'Ubercart donation product' module. You will want to create a new node of this type for each donation category you want to have on your site: node/add/donation. Again, I just had the one.

SettingValueNameDonationSKUDONATIONProduct and its derivatives are shippable.'un-checked'Default quantity to add to cartleave blank to disable qty fieldURL path settingsdonate

Ubercart Settings

Since Ubercart is a big monster it has many many settings. Too many to go through in detail, but I will add, that on top of what is listed below, you should also search through all the configuration categories found in admin/store/settings. Many of these are messages to the user, so for each occurance of 'order', 'orders' or 'products' that you see, replace them with 'donation' or 'donations'. This makes the checkout process more tuned to a donation system rather then a shopping cart.

Cart Settings: admin/store/settings/cart/edit

SettingValueContinue shopping element display+ noneCustom cart breadcrumb textdonateCustom cart breadcrumb URLdonate

Checkout Settings: admin/store/settings/checkout/edit

SettingValueEnable checkoutEnabledEnable anonymous checkoutEnabledHide shipping information when possibleEnabledUse collapsing checkout panesDisabledCollapse a pane when its..DisabledSend new customers a separate e-mailDisabledLogin users when new customer accountsDisabledNew customer accounts will be set to active.Up to you?

Checkout Panes: admin/store/settings/checkout/edit/panes

SettingValueCart contentsDisabledCustomer informationEnabledDelivery informationDisabledBilling informationEnabledPayment methodEnabledOrder commentsUp to you?Require e-mail confirmation ... anonymousUp to you?Allow anonymous customers to specify a new user account nameUp to you?Allow anonymous customers to specify a new user account passwordUp to you?Show the order total preview on the payment paneDisabled

Checkout Messages: admin/store/settings/checkout/edit/messages

Replace all occurrences of 'order(s)' with 'donation(s)'

Order Settings: admin/store/settings/orders/edit

The setting on this page that you will most likely want to change is 'On-site invoice template'. This is the template that will be used when the user views thier invoice. See the instructions below on creating custom email templates.

Order Workflow: admin/store/settings/orders/edit/workflow

SettingValuein_checkoutTitle: Entering Information

Order Panes: admin/store/settings/orders/edit/panes

Here you will most likely want to disable the 'ship to' pane under each category.

Payment Settings: admin/store/settings/payment/edit

SettingValueDefault payment details messageContinue with your donation to complete payment

payment Method Settings: admin/store/settings/payment/edit/methods

  • Credit Card - Default Gateway:
    • 'Test Gateway' for initial tests
    • Your preferred live payment Gateway for live/test transactions
    • Moneris.com in my case
  • Credit Card settings
    • Card number encryption key filepath: This is required before you can proceed through the checkout. Otherwise you will get an error at checkout. Use something like /home/keys.
    • Operate in credit card debug mode: Enabled for testing. Disabled for live.
    • Validate credit card numbers at checkout: Enable for testing cc transactions and when you go live. If disabled then the checkout process will complete without processing the cc information and the order status will remain pending.
    • Enable CVV text field on checkout form: Enable to include a field to process the 3 digit secure code on the cc
    • Credit card payment policy: Change 'orders' to donations.
    • Card processing failure message: Change 'order' to donation.

Payment Gateway settings: admin/store/settings/payment/edit/gateways

Specific details for the Moneris system follow below in the 'Trials and tribulations of integrating Moneris as a payment gateway' section.

SettingValueEnable this payment gateway for use'Enable' for each gateway you wish to use.

Store Display Settings: admin/store/settings/store/edit/display

SettingValueDisplay type for the main store administration pageDashboard with collapsed sub-menu linksPrimary customer addressBilling addressFooter message for store pages(Do not display a message in the footer.)


Custom code to further change the look of Ubercart

At this point we have changed as much of the configurable elements of Ubercart as 'humanly possible', so its time to delve into the code because certain things like the title of the "Shopping Cart" and form field names cannot be configured. I won't go through every single thing that I did, but I will try to give a good example of each type of modification.

CSS Injector overrides for page titles

Since we are trying to create a 'donation' system, some of the Ubercart page titles don't exactly lend well. "Shopping cart" isn't exactly the tone we want to set when trying to recieve a donation. There is definitely a programatic way to change the titles using the theme system, but I opted for quick and simple. CSS Injector allows you to do exactly what its name eludes to, inject css for configured pages.

Here is how:

  1. Create a new CSS Injector rule: admin/settings/css_injector/add
  2. Set the css code to: .section h1.title { display:none; }
  3. Select + Add on only the listed pages
  4. Set Pages to:
    • cart
    • cart/checkout/review
    • cart/checkout/complete
  5. Enable the 'Preprocess CSS' box.

Creating the above rule will hide the titles on the given pages. Now we want to replace them with new more suitable titles. To do this I just created three blocks. One for each page. I used

Your Donations


Review Donation


Donation Complete

respectively and added them to the 'Content Top' block region.


Creating custom email templates

At certain times, like upon checkout, completion emails are sent out. Ubercart formats these emails using defined templates. You can create your own templates to change the look and content of the emails. Ubercart has two default templates that are found in ubercart/uc_order/templates: admin.tpl.php and customer.tpl.php. There are many references to 'order' and 'products' and 'shopping' that I didn't want included in the emails that were being sent out so I copied and modified the customer template and saved it in the same location as donation.itpl.php.

There are several places where you will want to configure Ubercart to use the new customized template. One as mentioned above is when the user views thier invoice online. Configure this at admin/store/settings/orders/edit. Also, there are some pre-defined 'conditional actions' whose action it is to send out the emails. They are listed here: admin/store/ca. Essentially you will want to 'edit' each one that has Email in its title and then click on the actions tab. More specifically you will want to edit admin/store/ca/uc_checkout_customer_notification/edit/actions and select 'donation' as the 'Invoice template'. The other conditional actions that are sending emails are not using templates, but will have references of 'order' that you might want to change to 'donation'.


Overriding Ubercart form functions

Pretty much all of the Ubercart forms have fields that I wanted to rename for the sake of making it look more donation centered. A good example is the cart form. Its form id is 'uc-cart-view-form'. This form had three items I wanted to override. The 'products' and 'Qty' fields and the 'Update cart' button. I figured at first that I would be able to use hook_form_FormID_alter to change these fields, but it turns out that Ubercart defines its own Table API called tapi that it uses to build tables and links into forms. Tapi forms can not be overridden using hook_form_FormID_alter but they can be using hook_form_alter and you can filter based on its callback function. I actually went a different route, because I found this out after the fact. In my theme's template.php file. I added the following code:

/** * Implementation of HOOK_theme(). */ 
function yourtheme_theme(&$existing, $type, $theme, $path) { 
  $hooks = array(); // note for zen themes use: $hooks = zen_theme($existing, $type, $theme, $path); 
  // Add your theme hooks like this: 
  /* $hooks['hook_name_here'] = array( // Details go here ); */ 
  $hooks['uc_cart_view_form'] = array('arguments' => array('form' => NULL)); 
  $hooks['uc_cart_checkout_form'] = array('arguments' => array('form' => NULL)); return $hooks; 
  /* Implementation of hook_uc_cart_view_form() * * modify the ubercart view form. */ 
function yourtheme_uc_cart_view_form($form_state, $items = NULL) { 
  //override some form items to customize for donations 
  if(isset($form_state['items']['#columns']['image'])) $form_state['items']['#columns']['image']['cell'] = "Donations"; 
  if(isset($form_state['items']['#columns']['qty'])) $form_state['items']['#columns']['qty']['cell'] = "";
  if(isset($form_state['checkout']['#value'])) $form_state['checkout']['#value'] = "Continue"; 
  if(isset($form_state['update']['#value'])) $form_state['update']['#value'] = "Update Donations"; 
  $output = drupal_render_form('uc_cart_view_form',$form_state); 
  return $output; 

In the above code I first register a higher priority override function for the uc_cart_view_form rendering function. This means that the theme system will use my function for displaying the Ubercart cart view form.

The theme system looks for my override function as uc_cart_view_form but preceded by my theme name. In my function I do the following:

  1. change the products (image) field to "Donations."
  2. Disable the field title for the quantity(Qty) field
  3. Change the text of the 'Update cart' button to "Update Donations".


You can use this same technique to override any of the other Ubercart forms.

Note: Ubercart uses the "value" param of its forms' buttons to determine how to process the form and where to go next. Thus, this does not lend itself to allowing you to easily override the button text. I chose to simply leave it the way it was. However, say you wanted to change the text of the "checkout" button to "submit donations". If you use my method above to override the checkout button it will not go to the checkout page because the processing submit function, uc_cart_view_form_submit, switches based on the value "checkout". Instead of continuing to the checkout page, it will simply stay on the same page. This happens when I override the Update button as well, but in that case it doesn't matter, because I'm just sending it back to the same page anyway, so the update button still works.

If you were really ademant that the button needs to be overriden then you would have to change the button text as in the above method, then register your own submit function for that form. In your submit override you would have to alter the incomming $form and $form_state variables so that the values returned as 'op' (the button name) specify "checkout" rather then "submit discount" and pass them along to Ubercart's implementation of uc_cart_view_form_submit.


Trials and tribulations of integrating Moneris as a payment gateway

My troubles with integrating Moneris as a payment gateway actually had nothing to do with the uc_moneris module and its configuration, but more with Moneris itself and their out-dated convoluted documentation and lack of knowledgeable tech support people. Here are some pointers/facts that may save you a whole lot of time:

  • First you will actully need a user account to be able to read their API documentation. Go to http://www.eselectplus.ca/en/downloadable-content and click 'New User Registration'. It will take a few days before they send you your login credentials.
  • Once you have access to the documentation you can at least set up your system to test your donation system using Moneris.
  • Not all the relevant information is in the same documents and the links in thier documents are outdated and no longer work. If you are looking for a particular document then you should be able to find it somewhere on the site under 'downloadable content'.
  • NOTE: Before you start testing know that the penny value, yes penny value, of the transaction you are performing will determine the outcome of the test. Moneris uses the penny value to reject, accept, decline, etc. your test transactions. Also, depending on the test 'StoreId' you use you can test certain scenarios. For example if you want to test acceptance of a fake credit card's cvd value, you have to use their specific test 'storeId', 'API key' and 'Credit card #' It will save you a lot of time to look through some of the documentation below especially the ones that map penny values to return codes.
  • Here is a list of useful documents and what they tell you:
    • Integration Guide - general -> PHP Api : The most useful information in this document is a list of test 'storeIds', 'API Keys' and test 'credit card numbers'. It also describes some of the return codes and what they mean.
    • Others -> Test Environment Penny Value Response Table : Contains all the mappings between specific Credit Card Numbers, penny values and Response codes.
    • Others -> Test Environment CVD/AVS ResultTable : Contains all the mappings between specific penny values and response codes when you are using their very specific 'StoreId' and cc# that is configured to accept efraud(CVD/AVS) verifications. This is for testing the three digit code on the back of your credit card.
    • Others -> PCI-DSS Implementation Guide : Essentially outlines what they require in terms of security on your site before they will allow you to start using thier service. This includes an ssl certificate, statement of privacy for your users, regular third party security scans of your site to verify PCI compliance. Mcaffee offers this for $319/yr there are others out there as well.
  • To do real transactions you will need to purchase a Merchant Account. Once they have approved your application, which can take up-to several weeks, they will send you your Merchant Id and Store Id if you have signed up for e-commerce.
  • Now, to actually submit a transaction you require a 'StoreId' and an 'API key'. They send you the store id after your application is accepted, but to get an API key, you need to log into your merchant account and 'Activate your store'. Then you get your API key.
  • BTW, No tech support person or documentation ever explained this simple stuff and it made it incredibly frustrating as a first time implementer of a Moneris solution.

As for configuration of the uc_moneris module for Drupal, it is quite simple.

Moneris.com settings: admin/store/settings/payment/edit/gateways

SettingValueAPI VersionCanada or United StatesStore IDyour StoreId or test StoreIdAPI TokenMatching API tokenTransaction type to usePurchaseCVV/CVD RequiredRequired if you purchased this feature from MonerisUse Address Verification (AVS)Required if you purchased this feature from MonerisEnable VBV (Verified by VISA)Required if you purchased this feature from MonerisEnable VBV Strict ModeDisabledTransaction mode

  • Test sends transactions to Moneris Sandbox
  • Production to send live transactions to moneris.com


Good Luck and all the best with setting up your own Donations system. :)