2
Answers
Vote up!
2
Vote down!

How to allow User Payments

We have a Commerce site that takes event registrations from users and places them in a 'queue' for that event. Some of the events can range anywhere from $1000 up to $20,000 depending on various factors (team size, number of participants, whether or not you need amenities). So, we cannot accept credit payments in full up front, we need to allow users to make deposits at certain intervals. Deposit amounts and paid in full on an order determines their slot on said event- the event may only hold 20 teams, but we allow more than that to enter, thus, it comes down to who pays their dues on time when required.

Ultimately, what we need is for a customer to checkout and complete a registration signup, without payment information. Once they log in to view their order status, they need to see their balance on the order, and make payments.

Asked by: kevinquillen
on August 14, 2012

2 Answers

Vote up!
3
Vote down!

Here is how I ultimately did this.

First, I assessed what was going on in the Commerce Invoice module and determined I could not use this. We need to allow partial payments / deposits.

Second, we basically need exactly what administrators see on the backend when viewing orders.

Recreating this:

  1. Give the customer role 'Create Payments' and 'Edit own orders' Permissions
  2. In the Commerce Payments default view, add a Block display and override it.
  3. In this new view, adjust the Fields to your liking. I removed a couple for UX reasons.
  4. Create a custom module, and use the code below

To be somewhat consistent, I wanted to put tabs on the order display for a user so you could see order details and payments.

In a custom module, utilize hook_menu like so:

<?php
$items
['user/%user/orders/%commerce_order/view'] = array(
   
'title callback' => 'commerce_order_ui_order_title',
   
'title arguments' => array(3),
   
'page callback' => 'commerce_order_ui_order_view',
   
'page arguments' => array(3, 'customer', FALSE),
   
'access callback' => 'commerce_order_customer_order_view_access',
   
'access arguments' => array(3),
   
'type' => MENU_DEFAULT_LOCAL_TASK,
  );

 
$items['user/%/orders/%/payments'] = array(
   
'title' => 'Payments',
   
'description' => 'Make payments for this order.',
   
'page callback' => 'your_custom_module_payments',
   
'page arguments' => array(1, 3),
   
'access arguments' => array('view own commerce_order entities'),
   
'type' => MENU_LOCAL_TASK,
   
'file' => 'includes/your_custom_module.payments.inc',
  );
?>

The first item above I basically followed what was in commerce for the order display callback, and made /view a default task to get setup for additional tab(s), Payments. This callback is going to render a page, and call our view.

<?php
function your_custom_module_payments($uid, $order_id) {
  global
$user;
 
$order = commerce_order_load($order_id);

 
// not sure if this will work longterm, in the case of admins creating orders for users
 
if ($user->uid != $order->uid) {
    return
drupal_access_denied();
  }

 
drupal_set_title('Payments');

 
$output .= commerce_embed_view('commerce_payment_order', 'your_new_view_display_id', array($order_id));
  return
$output;
}
?>

This basically checks to see that the current user is the owner of the order they are about to make or view payments against, then embeds the new view we created from the default off of Commerce Payments. I could not find a better method of doing this- I would rather check access at the menu item level, but every attempt resulted in Access Denied.

One more additional step you will want to take is to alter the Cancel link that is output in the payment form for a regular user. If not, it will attempt to take them to admin/ area by default. I just

<?php
function your_custom_module_form_commerce_payment_order_transaction_add_form_alter(&$form, &$form_state) {
  if (!empty(
$form_state['payment_method']) && !user_access('administer payments')) {
   
$form['actions']['submit']['#suffix'] = l(t('Cancel'), 'user/' . $form_state['order']->uid . '/orders/' . $form_state['order']->order_id . '/payments');
  }
}
?>

Here is the result:

This is now what a user sees when viewing their order, clickable with a tab between order details and Payments.

This is (for us) a larger step toward having customer balance(s) functionality. We have some D6 Ubercart clients who have running totals, not exactly storefronts. As long as they keep up on payments they still receive weekly deliveries.

Answer by: kevinquillen
Posted: Aug 14, 2012
Vote up!
1
Vote down!

I forgot to note above (can't edit) that I also disabled the Payment pane for now from the checkout process.

A further step would be to assess if the user is registering for an event, or simply buying a tshirt. In the latter case, we do want to take full payment up front- but it is okay to never process their order until they pay for it (Rules updating order statuses) or simply cancel it automatically after 2 weeks. You could use redirects or user instructions funneling them to the Payment area for that order, and the above still works for both cases.

I am using Commerce, Commerce Registration, and Entity Registration modules for this functionality.

Answer by: kevinquillen
Posted: Aug 14, 2012

Comments

Kevin posted this in IRC directly after adding the amazing amount of awesome content, "on second thought, i suppose you could dupe the master view in the Commerce Payments view, change the path to (path)/view, and make it a Tab, then create the Payments view tab, and not have any hook menu callbacks or code at all other than the form alter for the cancel link"

Thanks Kevin!

- Josh Miller on August 14, 2012