Drupal Commerce 設定依不同的客戶群組顯示不同的價格

雖然都用Ubercart,不過還是記錄一下

Drupal Commerce - Different prices for different customer groups
http://jamestombs.co.uk/2012-09-14/drupal-commerce-different-prices-different-customer-groups


What are we looking to do?

When you have an online store, by default a product has a set price which is what everyone pays. You may have discounts through voucher codes but occasionally you want to offer a different price to shoppers i.e. wholesalers.
So what we will be doing is creating a new role called 'Wholesaler', adding a new price field to our product, then we will set up a rule which will calculate the right price for the wholesaler.
The tutorial will be focused around a basic Drupal 7 install with the Commerce module (and the other relevant modules installed).

Tutorial

Create user role

Go to admin/people/permissions/roles and add a new role.
Whenever you have a wholesaler wishing to use the site, you will need to give the wholesaler role to that user.

Set up a new price field

Go to admin/commerce/products/types/product/fields and in the Add new field, type Wholesaler price.
For the field type select Price, then chose the Price with currency widget type and add the field.
On the settings form, it is up to you whether you want to make it required etc. But leave the Number of values set to 1.

Set up the pricing rule

Go to admin/commerce/config/product-pricing and click the Add a pricing rule link.
For the name, just enter Wholesaler price rule.
Under events, it will automatically set the event called Calculating the sell price of a product.
Skip past to the Conditions section and click the Add condition link.
From the drop-down, select Entity has field.
Under Entity, for the Data selector set it to commerce-line-item. From the drop-down this will be listed as commerce-line-item (Product line item).
For the field, select commerce_product. Click Save.
Add another condition, and select Entity has field again. For the Data selector, choose commerce-line-item:commerce-product. In the drop-down you will need to select commerce-line-item... (Product line item) (not the ...) which will bring up a few more options, from these selectcommerce-line-item:commerce-product (Product).
Then in the field box select field_wholesaler_price or whatever you called the field in step 2.
Lastly, had a new condition called and select User has role(s). From the data selector chosesite:current-user. You can choose this by going to site:...(Site information) then choosing site: current-user (Logged in user).
Then in the Roles section click your wholesaler role.
Save the condition.
Finally, under Actions click Add action. In the drop down under Commerce Line Item, select Set the unit price to a specific amount.
The Data selector should already be set to commerce_line_item.
Under Amount, click the link which says Switch to data selection.
From the drop down select commerce-line-item:... (Product line item) then select commerce-line-item: commerce-product:... (Product).
Then select your price field which will be commerce-line-item: commerce-product: field-wholesaler-price:... (Wholesaler price). Then select commerce-line-item: commerce-product: field-wholesaler-price: amount (Amount).
Leave the Price component type set to Base price. Under Price rounding mode it is up to you how this is set.

Conclusion

If you now set up a dummy user, give them the role wholesaler and login as them and browse the site, all the prices will now be showing the wholesaler price by default. Log out and the prices will go back to retail prices.
You can set up multiple different pricing structures thanks to Drupals fields module which allows an infinite amount of price fields.

Potential problem

This may cause a few issues for people on how they want data to appear. When a wholesaler is logged in they will see the wholesaler price and not the retail price. If you want to show the retailer price as well you will have to alter your product display template file to show both prices.

Creating roles/fields/rules automatically through code

If you are importing data to your site or you have a lot of different price structures for different roles then you can import them.

Creating the role

Through code, this is very simple:
$role = new stdClass();$role->name 'Role name';user_role_save($role);?>
That will create a new role called Role name. Very simple to do.

Creating price fields per role

Rather than adding this code to a custom function, I would recommend usinghook_user_role_insert($role). This way if you create a role through the admin screens of the site all the heavy lifting has been done for you.
function MODULE_NAME_user_role_insert($role) {
  
// Create and add the new price field to the product
  
$field_name 'field_price_role_'$role->rid;
  if (!
field_info_field($field_name)) {
    
$field = array(
      
'field_name' => $field_name,
      
'type' => 'commerce_price',
      
'entity_types' => array('commerce_product'),
      
'translatable' => FALSE,
      
'cardinality' => 1,
    );
    
$field field_create_field($field);
    
$instance = array(
      
'field_name' => $field_name,
      
'entity_type' => 'commerce_product',
      
'label' => 'Price for 'str_replace("/"" "$role->name),
      
'bundle' => 'product',
      
'description' => '',
      
'default_value' => NULL,
      
'deleted' => FALSE,
      
'required' => FALSE,
      
'settings' => array(
        
'user_register_form' => FALSE,
      ),
      
'widget' => array(
        
'type' => 'commerce_price_full',
        
'module' => 'commerce_price',
        
'active' => 1,
        
'settings' => array(
          
'currency_code' => 'default',
        ),
      ),
      
'display' => array(
        
'default' => array(
          
'label' => 'above',
          
'type' => 'hidden',
          
'weight' => 1,
          
'settings' => array(),
        ),
        
'line_item' => array(
          
'label' => 'above',
          
'type' => 'hidden',
          
'weight' => 0,
          
'settings' => array(),
        ),
        
'node_teaser' => array(
          
'label' => 'above',
          
'type' => 'hidden',
          
'weight' => 0,
          
'settings' => array(),
        ),
      ),
    );
    
field_create_instance($instance);
  }
}
?>
Here we are creating a new field of the name field_price_role_XXX where XXX would be the role ID. This will always be unique so you won't have any problems with name clashes.
Once the field is created, we create an instance of it on the commerce_product entity type. If you have a more complex set up with different product types you may need to set up multiple instances.
The other thing you may want to handle, is the deletion of a role. Once the role is deleted the field is no longer required. So you can use hook_user_role_delete($role).
function MODULE_NAME_user_role_delete($role) {
  
$field_name 'field_price_role_'$role->rid;
  
field_delete_field($field_name);
}
?>
The code is very simple and having the role ID used in the field name makes it extremely easy to know which field belongs to which role.
The field will still exist in the database until cron has run.

Automatically setting up a pricing rule

Rules can be defined in code by creating a MODULE_NAME.rules_defaults.inc file within your module folder.
What we do is get all the roles from the database, remove the standard authenticated user as this will pick up the default price automatically. Then we will set up a rule per role.
function MODULE_NAME_default_rules_configuration() {
  
$configs = array();
  
$roles user_roles(TRUE);
  unset(
$roles[2]); // Get rid of default authenticated user
  
if (count($roles) > 0) {
    foreach (
$roles as $rid => $role) {
      
$rule '{ "rules_product_pricing_for_role_'$rid .'" : {
          "LABEL" : "Product pricing for '
$role .' role",
          "PLUGIN" : "reaction rule",
          "REQUIRES" : [ "rules", "commerce_line_item", "commerce_product_reference" ],
          "ON" : [ "commerce_product_calculate_sell_price" ],
          "IF" : [
            { "entity_has_field" : { "entity" : [ "commerce-line-item" ], "field" : "commerce_product" } },
            { "entity_has_field" : {
                "entity" : [ "commerce-line-item:commerce-product" ],
                "field" : "field_price_role_'
$rid .'"
              }
            },
            { "user_has_role" : {
                "account" : [ "site:current-user" ],
                "roles" : { "value" : { "'
$rid .'" : "'$rid .'" } }
              }
            }
          ],
          "DO" : [
            { "commerce_line_item_unit_price_amount" : {
                "commerce_line_item" : [ "commerce-line-item" ],
                "amount" : [ "commerce-line-item:commerce-product:field-price-role-'
$rid .':amount" ],
                "component_name" : "base_price",
                "round_mode" : "1"
              }
            }
          ]
        }
      }'
;
      
$configs['rules_pricing_per_role_'$rid] = rules_import($rule);
    }
  }
  return 
$configs;
}
?>
This produces the same rule as we did through the admin interface but will create a new rule per role.
Note that the code within $rule is the result of an export from the Rules UI module. So you can make your own rule within the Rules UI then export it and use that to create your rules dynamically.
You will need to run cron each time you add a new role for the rule to become active and take affect. Once cron has run it will appear in the Rules UI, at which point you can override any part of it.

留言

熱門文章