Summary of prices, and price handling
Overview
Unfortunately pricing is not as simple as a decimal, because the price stored with a product is simply a starting point. By the time a customer completes checkout, the price may have discounts, fees, taxes, and nearly unlimited unforeseen modifications. In order to handle the wide variety of pricing models, taxes, and other price alterations, we must create a well defined, flexible price system.
During the San Francisco, and Paris sprints, we had the ability to gather input from various people from multiple countries, with a wide range of customer experience. We believe we have come to a good understand of what a price is, and the feature requirements of a price system.
Definitions
- Components of a Price
- A price is defined as an amount, and a currency. Prices must be stored with the currency indication.
- Base price
- The base price is the amount+currency associated with a product, line item, or any other item implementing a price field. The base price is the price displayed on edit forms, and is not modified throughout it’s display life cycle.
- Current price
- The actual price, including discounts, fees and taxes. This price always starts at the base price, and is allowed to be modified through methods provided by the price system.
- Display price
- The site admin should be able to decide how prices are displayed through field formatters. These display options will include price theming(currency symbol, prefix/suffix) as well as the ability to select the price source(base price, altered price).
- Altering a price
- Prices should support alteration through code, and user configurable rules, however it is not up to the price itself to handle user alteration because it is dependent on the implementation of the price. The entity implementing a price should fire triggers during the necessary points in the load/save/display process, based on the individual use case.
- Price logging
- All modifications to a price should be logged as part of the price. This will allow other modules to summarize modifications to a price, such as inclusive tax, and discounts. Additionally this information should be saved with orders to ensure price modifications can be tracked after an order is completed.
- Price formatting
- The number format of a price(1.000,00 vs 1,000.00) is handled at the language level. The currency symbol is defined by the currency. Prefixes / Suffixes hare handled by the display formatter.
Components
The price system will be comprised of multiple sub systems, which will work together to provide the end user with all of the functionality needed to properly handle pricing.
- The price field
- The price field will be defined by the fields api, and can be attached to any Drupal entity. Although we will focus on how prices will be attached to products, price fields can also be attached to orders, line items, nodes, taxonomy terms.
- The price object
- The price object is the heart of the price system. An object is required in order to ensure prices can not be changed without logging. The price object will contain properties for the base currency, base price, current currency, current price, and the log of all changes to the price itself.
The price object will also contain a small set of methods allowing for price modifications, and providing access to a subset of logged changes, based on category of modifcation, the module doing the modification, and the description of a modification.
- Pricing rules
- The price object itself will not provide rules integration, but rather the entity itself, will provide integration to the rules system. This will provide rules with the necessary context to make pricing decisions.
This will require module developers to carefully consider at which points prices may need to be modified, such as during loading, before displaying, when added to the cart, various points during checkout, etc.
- Views integration
- The price system should be fully integrated with views. This may present sorting and filtering issues, because the base price may not match the display price.
- Display formatters
- The price system should ship with base display formatters allowing for prices to be displayed with/without all major categories of changes, or the ability to only display the sum of the changes. For example, we may want to display the sum of taxes per product, or the the price of the product tax inclusive and tax inclusive. These formatters should be available to the field api, as well as views.
- Field widgets
- The field widget settings should allow the store administrator to lock the price currency field to any one of the enabled currencies, or allow users to select a currency for each price entered.
Summary
If you're still with me, I commend you. For a short summary, prices need to be extremely flexible, however we must be able to determine how the price was changed, and provide enough data for summaries of changes to prices. Ultimately the majority of the logic involved in modifying prices will be placed within Rules, and will be accessible by a liberal use of rules events(triggers).
Finally, when we sort out the ability to modify prices at every corner, we need to ensure we provide the same flexibility in displaying prices. By focusing on display formatters, developers should be able to add support for any display formats we do not anticipate, and users will have the ability to select the proper format for a given situation.
Comments
Looks like a great summary!
Looks like a great summary! The only tweak I'd say is I think the default currency format makes the most sense in the currency definition level, not at the language level. Otherwise we'd have to load in a whole new language for every currency we wanted to enable. If someone wanted to view a currency not traded in their country, I think it's reasonable to expect them to understand the different thousands / decimal separator.
Currency format vs number format
I believe the idea there was not so much the format of the currency, but the formatting of the number. I.E. The placement of the € symbol is part of the currency format. The placement of the thousand separator and decimal separator is language specific.
A great example of this is the Canadian dollar. It's currency code is CAD, the symbol is $. In the english speaking portions of Canada numbers are formatted 1,000.00. In french speaking regions, numbers are formatted 1.000,00. The entire country uses the same currency, however the same price can be represented in to different number formats, based on the local language.
My personal thought is that the number format itself is language/region specific. The currency information itself is currency($, usd, dollar) is definitely currency specific.
I can see that, I just didn't
I can see that, I just didn't know if it introduced unnecessary complexity. i.e. I'm used to seeing currency formatted as $1,000.00, but if I saw $1.000,00 or $1 000,00, I can easily figure it out thanks to the fact that numbers are still numbers. : D
From a technical standpoint, the simplest thing to do will be to store number formatting with the currency formatting guidelines. I'd target that first, and if we can get a simple way to make this translatable for different languages, we can go there before we hit 1.0.
Multi Currency?
Have you considered shops that might sell in more than one currency e.g. USD, GBP and EURO?
In most situations like that, they have different prices for each that are not simply the stores primary price (say GBP) times the exchange rate.
If I understand what was
If I understand what was written it seems that each product has just a single price, which I agree is limiting. If the intention is that each different currency would require a new product can I suggest that we consider implementing something I posted before about possible improvements to product prices (http://www.drupalcommerce.org/node/72)? This system would give single products the possibility of many prices. Adding a currency field to the list of fields I mentioned would make everyone happy and at the same time make product pricing much more flexible than it currently is.
I don't want to diminish the hard work that is being put in and I understand that the functionality I mentioned could possibly be considered a contrib module, but what mikejoconner has detailed sounds practically identical to the way prices were already done (with the addition of a currency which was available as a global setting previously). I had been hoping we would see some improvements concerning pricing.
Thanks for the feedback
I apologize for any confusion. I probably should have outlined some of the main differences.
The major difference in the new system is prices are not simply decimals. If a price is simply a decimal, you had no way of knowing how you arrived at the price you received. This may not sound like a major improvement at first glance, but it will result in a significantly improved system.
Moving forward, you will know if your product price is in dollars or euros, you will know if it is tax inclusive or tax exclusive, and you will be able to easily display a summary of any taxes that have been included in the product price. Basically every price will contain its starting point, its current value, the a log of the changes that brought it to its current price. Basically the price contains its context at all times.
This will allow us to provide things like views fields which summarize changes. i.e the user could display . We could also create a display formatter that displayed a on sale image if the price its displaying had a discount applied.
Another other main difference is the "price handler" will be Rules. This provides both developers and users with a method of modifying prices. Instead of having to code a custom price handler, you will be able to define price rules through a common interface.
We will also focus on using user selectable display formatters to display pricing. You will be able to display pricing in multiple ways, in multiple locations, without crazy theme overrides.
We have
The price field itself should support storing multiple prices, one for each currency. You will then be able to use Rules to select the proper price based on customer information. Furthermore you could add multiple price fields, and use rules to support tiered / preferred customer pricing, per currency.
I'm unclear concerning the
I'm unclear concerning the current price. You mentioned that it includes discounts/taxes, does this mean it is a calculated field? (ie it can't be edited manually)
What a coincidence ! I was
What a coincidence ! I was just working with price hook_uc_price_handler (gave me a headache) for a reservation system...
I hope this is going to be flexible enough to handle travel reservation systems, in which prices are so random and vary (at least) by the date you make your reservation and the date your reserve for...
For my case using uc2 on d6, i just ended up externalizing quite every price calculation and forcing a price into hook_cart_item with qty 1
Oh well, i better go get some sleep...
Real time pricing
We didn't discuss real time pricing, but we did discuss the ability to support price lists. The general idea is that many customers have predefined prices per product, which are frequently updated by the companies marketing department.
In a situation like this, you would simply right a rules plugin to pull the proper price from the external source, which could be a web service, a file on the local disk, or anything in between.
Yes rules is a great option,
Yes rules is a great option, but what about product search ? I mean if product price has to have some context/input (ex. reserved date + qty of nights), Listing products and having rules pull/calculate the price for each product in the list (+ stocks and availability) would be a performance hog i think
I don't know if it makes sense but i suggested something on http://www.drupalcommerce.org/node/118#comment-284
Variable Base Currency with Real-Time Display Pricing?
In my view each Catalog Item should have 1 base price with 1 base currency. The Shopping Cart would be displayed in a user selected language and currency.
The displayed price would be calculated real-time by converting the base price from the base currency to the display currency.
Example:
cart language = english
cart currency = USD
USD/Euro real-time FX rate = 0.743
USD/GBP real-time FX rate = 0.629
item-1 base price/currency = 74.3 Euro
item-2 base price/currency = 62.9 GBP
=========================================
item-1 display price/currency = 100 USD
item-2 display price/currency = 100 USD
=========================================
How does Drupal Commerce work?
Shouldn't the "price object"
Shouldn't the "price object" be called "money object" since it is a monetary value object and that it'd be used on orders line items, total...etc
A reference to some interesting material :
http://martinfowler.com/ap2/quantity.html
The Shoulders of Giants
After following this project for the last few months there seems to be a lot of effort dedicated to reinventing the wheel. I fully understand the need to build a new e-commerce solution from the ground up. Some of the core parts of Ubercart were not designed with scalability and flexibility in mind. However, before we start laying the foundation, may I suggest we stand on the shoulders of giants and see things from their point of view.
There are countless numbers of other projects that have successfully tackled this problem:
PS
Sorry I can't get any links past the filter.
I'll update the post to make
I'll try to update the post to make sure the links work. There's some excellent info in those links, so thank you for gathering them up! I'm not sure they're all directly applicable to this thread, as some are related to inventory management, product presentation, etc.
However, the overlapping parts are encouraging. There's nothing too tricky to storing a value and a currency symbol, and I'll be digging through those for currency code and format definitions. I definitely don't want to reinvent that list. : P
This specification is also more from a technical standpoint of how will we track alterations to product prices displayed to customers / on orders... i.e. how can we enable a module to add tax to a product price for display and then find out how much was added later to summarize all tax values in a non-calculated tax line item on the order. If any of those links discuss this sort of technical requirement, I'd love to give it a read.
Tax Support
Take a look at this for more details on Taxes:
That link would be excellent
That link would be excellent in one of the tax threads, for sure.
Price Rules
I know it's a bit early, but since we're planning to have rules integration for prices it would be nice to have an embedded view that lists the rules that apply to a products price right below the product price proper (or as a vertical tab).
The other use case I would
The other use case I would add is that of prices varying based on region. For example, a client of mine that currently runs an Ubercart site is an international book publisher.
The prices of their books actually vary based on which region they're shipping the books, with the countries of the world divided into three regions - the developed world (U.S, U.K etc.), the Asian Region and the African region, with prices being the lowest for the African region countries.
When the site was built two years ago, there was no way (at least not without heavy custom coding for which the client didn't have a budget) to define prices in that manner and they had to forego a century old tradition of differential pricing for their online book store.
Would the price system described above make it possible to address this requirement? It isn't immediately evident to me that it would, but I may have missed something.
API HELP..
Hi,
is there an API to call the amount of a product?
right now im using this code
$product = commerce_product_load_by_sku($sku);
print_r ( $product->commerce_price[und][0][amount] );
but the value that i got is 100000 instead of 1000.00
thanks