Summary of prices, and price handling
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.
- 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.
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.
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.