Would it be possible to incorporate the registration price into the registration node?

It seems pretty long winded to require a new registration type for each differently priced registration. Especially so, with all the permissions settings that need to be configured for each registration type.

I agree this is not a big effort for an occasional conference, but for an organisation running a great many events this would quickly become unmanageable.

Comments

MrPaulDriver’s picture

Issue summary: View changes
stufke87’s picture

I am looking for the same thing. Did you manage to fix this or did you find an other solution?

lance.gliser’s picture

This can be done through a custom module already, actually. Here's the relevant bits:

File: custom.module

This file is being used as a routing file a the logic in custom/registration/registration.module.inc

/**
 * Registration API
 */
function custom_registration_entity_settings($settings){
  module_load_include('module.inc', 'custom', 'registration/registration');
  return _custom_registration_entity_settings($settings);
}

/**
 * Validates data for the registration price and updates the data being stored
 * to match the standard commerce price data format
 */
function custom_registration_entity_settings_element_price_amount_validate($element, &$form_state, $form) {
  module_load_include('module.inc', 'custom', 'registration/registration');
  _custom_registration_entity_settings_element_price_amount_validate($element, $form_state, $form);
}

/**
 * Modifies the pricing of registrations to allow for our custom logic
 *
 * Returns an array formatted as a standard commerce price object.
 *
 * @param Registration $data
 * @param $info array
 * @return array
 */
function custom_registration_commerce_calculate_price($data, $info){
  module_load_include('module.inc', 'custom', 'registration/registration');
  return _custom_registration_commerce_calculate_price($data, $info);
}

custom/registration/registration.module.inc

/**
 * @file Contains logic for registration customization
 * Note: While registrations were install *for* events,
 *   they are not exculsively programmed against them.
 *   Anything could have a registration added. Stay generic.
 *
 * Note: There IS a registration module.
 *   Ensure all code uses custom_registration namespace
 */

/**
 * Hooks
 */

/**
 * Provide a form API element exposed as a Registration entity setting.
 *
 * @param array $settings
 *   Existing settings values.
 *
 * @return array
 *   A FAPI array for a registration setting.
 */
function _custom_registration_entity_settings($settings) {
  // Only add unique settings on a per entity basis, if we have an entity!
  if( empty($settings['entity_type']) || empty($settings['entity_id']) ){
    return array();
  }
  // Get the entity we're registrating against
  $entities = entity_load( $settings['entity_type'], array($settings['entity_id']) );
  $entity = $entities[ $settings['entity_id'] ];
  // Get the registration settings
  $registration_type_id = registration_get_entity_registration_type($settings['entity_type'], $entity);
  $registration_type = registration_type_load($registration_type_id);
  $commerce_settings = $registration_type->registration_commerce_settings;
  // If commerce based registration is not enabled, bail out
  if( empty($commerce_settings['enable']) ){
    return array();
  }

  $form = array();

  $form['price'] = array(
    '#title' => t('Price'),
    '#tree' => TRUE,
    '#type' => 'fieldset',
    'amount' => array(
  	  '#type' => 'textfield',
      '#title' => t('Amount'),
  	  '#required' => TRUE,
      '#field_prefix' => commerce_currency_get_symbol($commerce_settings['price_defaults']['currency_code']),
      '#size' => 10,
      '#element_validate' => array(
        'custom_registration_entity_settings_element_price_amount_validate'
      ),
    ),
    'currency' => array(
      '#type' => 'item',
      '#title' => t('Currency:'),
      '#markup' => $commerce_settings['price_defaults']['currency_code'],
    )
  );
  if( isset($settings['settings']['price']['amount']) ){
    $form['price']['amount']['#default_value'] = $settings['settings']['price']['amount'] / 100;
  } else {
    $form['price']['amount']['#default_value'] = $commerce_settings['price_defaults']['amount'] / 100;
  }

  $form['#validate'][] = 'custom_registration_entity_settings_validate';

  return $form;
}

/**
 * Ensures the type of data for the price is correct
 * and stores it correctly for commerce
 */
function _custom_registration_entity_settings_element_price_amount_validate($element, &$form_state, $form){
  $value = $element['#value'];
  if ($value != '' && !is_numeric($value)) {
    form_error($element, t('%name must be a number.', array('%name' => $element['#title'])));
  } else {
    // The commerce settings are stored as integers. Multiple the value by 100 to match
    form_set_value($element, $value * 100, $form_state);
  }
}

/**
 * Modifies the pricing of registrations to allow for our custom logic
 *
 * Returns an array formatted as a standard commerce price object.
 * This is the price *per* ticket. Each space requested is represented
 * as quantity in the cart multiplied by the price returned here.
 *
 * @param Registration $data
 * @param $info array
 * @return array
 */
function _custom_registration_commerce_calculate_price($data, $info){
  // Get registration type defaults
  $registration_type = registration_type_load($data->type);
  $commerce_settings = $registration_type->registration_commerce_settings;
  // Get the entity settings
  $entity_settings = registration_entity_settings($data->entity_type, $data->entity_id);
  // Setup a basic pricing return
  $price = array(
    'amount' => 0,
    'currency_code' =>
      ( !empty($commerce_settings['price_defaults']['currency_code'])?
        $commerce_settings['price_defaults']['currency_code'] : commerce_default_currency()
      ),
  );

  // Nothing to do
  if( empty($entity_settings['settings']['price']['amount']) ){
    return $price;
  }

  $slots = $data->count;
  $price['amount'] = $entity_settings['settings']['price']['amount'];;
  return $price;
}

I do kind of wonder why this isn't a stock feature... Would make sense. Maybe the authors would be kind enough to integrate this code?

MrPaulDriver’s picture

This is a bit over my pay grade, but I too would welcome an opinion from the maintainers.

gcb’s picture

Category: Support request » Feature request

This is a good feature request: I'll look into how we might accommodate this. A little more about how it works currently:

1. It's still in beta! Partly because we are still working this stuff out.

2. Because pricing for these things is always extremely custom in our experience, the built-in price tool is intentionally simple. You can set your own prices by implementing "hook_registration_commerce_calculate_price". Here's an example from one of my projects:

/**
* Implements hook_registration_commerce_calculate_price().
*/
function custom_module_registration_commerce_calculate_price($registration, $info) {
$result = array();
$registration_wrapper = entity_metadata_wrapper('registration', $registration);
$event = node_load($registration->entity_id);
$event_wrapper = entity_metadata_wrapper('node', $event);
$price = $event_wrapper->field_registration_price->value();

$result = array(
'amount' => $price * 100,
'currency_code' => $event_wrapper->field_currency->value(),
);
}

return $result;
}

This essentially does exactly what you are requesting: it uses a field on the node (field_registration_price) to set the price.

Perhaps the most sensible thing would be to have the pricing UI on the registration type allow you to pick a price field to use for the price, and to look for that field on the Registration's host entity.

gcb’s picture

Status: Active » Fixed

commit #015ef35 offers an initial implementation. You'll now see a field selector on the registration commerce settings tab on your registration type. It only displays "Price" fields. If you add a Price field to your host entity type and set the value, then point the registration type to that field, you should have what you want here.

MrPaulDriver’s picture

Thanks for this. I'm a bit busy with another project but hope to take a close look very soon.

alibama’s picture

I'm testing this now - if I add a price field to the registration I still can't override the value set in registration commerce field - whatever value in there seems to win...

hold up - I may have misunderstood how this works, back in a sec - ok yeah = works great! thanks

gcb’s picture

Don't add the price field to the registration type: that would let the registrants pick their own price. Look at my instructions again:

"If you add a Price field to your host entity type".

So if you have an Event Content Type, add a Price field to that Content Type. The same content type that has a Registration field that links to the Registration Type.

alibama’s picture

yeah - sorry about that = registration_commerce +1, my literacy comprehension -1

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.

yaach’s picture

@gcb

I have added a price field for my content type. I need multiple price tiers, so I made the field with unlimited values and then on a node of my custom content type I set the price field with three values, $20, $10, $0. Then under the Registration Commerce Settings tab of the Registration Type I am using on my custom content type, I am selecting the price field to be used.

On another browser, I go to my node landing page and type in my email and click Register, it takes me to the Shopping cart with value $0 for registration.

At what point I can make the user choose the price they need to pay: $20, $10, $0 and then the chosen price should be carried out to the shopping cart.

Please help!

gcb’s picture

That's not supported with the automated price setter, I'm afraid. You'll need to add a field to your registration type to allow the user to select a price, and implement hook_registration_commerce_calculate_price() to set it. You can probably do some fancy stuff with a hook_form_alter to allow the price options to be selected on the event edit screen, and then insert those options on the registration form, if that's a requirement.

yaach’s picture

On comment #9 you mentioned "...registrants pick their own price...", that's probably what I am looking for. My use case is that an event has multiple prices tiers and actually will depend on the user role, but that's a more complicated solution. I would be happy if the registrant can choose the price.

gcb’s picture

Sorry if my answer in #9 implied that the module would do this all with just configuration: you'll have to write custom code to make that work. Here's an example:

/**
 * Implements hook_registration_commerce_calculate_price().
 */
function my_module_name_registration_commerce_calculate_price($registration, $info) {
    $registration_wrapper = entity_metadata_wrapper('registration', $registration);
    $price = $registration_wrapper->field_selected_price->value();
    $result = array(
      'amount' => $price * 100,
      'currency_code' => 'USD',
    );
    return $result;
}