You are here

Drupal commerce and rules: changing the product price dynamically

Drupal Commerce was made to work for selling and buying products that have a regular set price.  There are many add-on contrib modules you can use to set a discount and other ways of modifying the price, but again, the expectation is that you're selling a product that does have some sort of regular base price.

Well, what if that's not the case?  What if you want to use Drupal Commerce to allow users to pay the invoices they owe you, for example?  In that case, you'd have a product called 'Invoice', whose price is completely unknown.  One user may need to pay a $10.00 invoice, while another may owe you $230.50.  Drupal Commerce can still accommodate such scenarios, but you will need to create some custom rules to make it work.

Module prerequisites

Create the 'Invoice' product

  • Create a product called 'Invoice'
  • Set its price to 0.00: it doesn't make sense to set any other price for this, since it's completely variable for each customer that will be paying
    • We will set it later automatically for each user through a rule
  • Create a product display for your 'Invoice' product, just like you would normally
  • For more information on creating products and product displays, look through the Drupal Commerce documentation. Since I am not doing anything out of the ordinary here yet, I will not go into a detailed tutorial on creating a regular product.

Give users the ability to set their price

  • Download and enable the Commerce Customizable Product module
  • Go to Administration > Store > Configuration > Line item types and create a new line item type called 'Invoice'
    • While fields you create for the product (created in the previous section) will apply to the product every single person purchases, field created here, in the line item types section, can differ in value for each individual purchaser!
  • Go to 'Manage fields' for this new line item type and add the two fields that we will want to vary for each customer
    • Invoice number (Integer field type): the invoice number they are paying
    • Amount (Price field type): this can be a full or partial payment (in my case)
  • To include these 'dynamic' fields will each user will fill in independently of other users, go back to your Invoice's product display node and hit the 'Manage display' tab.
    • Configure the 'Product Reference' field you are displaying here (every product display should have a product reference field) to use your newly created 'Invoice' line item type.  By default it uses the 'Product' line item type which has no special extra fields (unless you've added some yourself).
    • Save and make sure your extra fields are displayed in the product view.
      (In my example below, I have three extra fields in my Invoice custom line item type, and they are all displayed under my Invoice product for each customer to fill out separately).

Set invoice price to what the user has entered

If you don't do anything else, there is a big, big problem with the above implementation - if somebody tries to buy the 'Invoice' product, they will end up entering in all their correct data, but will check out by paying you exactly $0.00, because that's the product's price currently.  We have to go a step further and, using rules, set the product's price to whatever the user has entered into the 'Amount' field you set up above during the checkout process.  Here is a simple version of that rule (though mine has some additional extras)

  • Create a new rule called 'Update invoice amount' which is triggered by the event 'Calculating the sell price of a product'
  • Add a condition 'Entity has field' and enter in 'commerce-line-item' as the entity and select the amount field you added in earlier as the field.  In my example, it's 'field_amount', but I am not sure what the computer name for yours is
    • We only want to apply this field when we're dealing with a product that has our special 'Invoice' custom line item type which includes a custom amount field, right??
  • Add an action of 'Set the unit price to a specific amount'. 
    • The line item should be set to 'commerce_line_item'
    • The amount should be set to 'commerce-line-item:field-amount:amount'
      • Again, if the computer name of your amount field is something else, just plug that in instead of my 'field-amount'
      • If you did not create your custom Amount field as a Price type field, you won't see the :amount option, so you may want to go back and fix that.

Test

  • That's all!  Go ahead and test the above setup with some small amounts or payments to a developer/testing payment gateway.
  • Let us know if you've found other creative ways to do the above.  I'm sure this is not the only trick to accomplish that, and would love to hear your versions.

Share

Comments

Thanks a lot for your entry! I think pricing rules are a greate feature and provide a lot of flexibility, but what's missing is a way to update the product price display via ajax on the product price.

Do you know a solution how to solve that?

Just to clarify: you don't have to worry about users checking out with the product price set by somebody else. What is being changed is the *line item* amount, not the product price amount. Every line item is a unique entity in a customers cart or on an invoice.

You're absolutely right.  Thanks so much for this comment - I think it will help clarify what line items are and how they work.  I have worked with Drupal Commerce so much more extensively since first posting this and have a much deeper understanding now myself.  I just forgot to come back and update my tutorial as I figured more out, so I appreciate the push here: I've updated the offending paragraph :-).

Another way to think about it is that line items are unique for each order the way the *tax* would be for that order, so changing a line item shouldn't affect anything but that one unique order that it is a part of.

Add new comment

Plain text

  • No HTML tags allowed.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.