shuup.core.pricing package
Submodules
shuup.core.pricing.default_pricing module
- class shuup.core.pricing.default_pricing.DefaultPricingModule[source]
Bases:
PricingModule
- identifier = 'default_pricing'
- name = 'Default Pricing'
Module contents
Shuup modular product pricing functionality.
The pricing module in use is declared by the
SHUUP_PRICING_MODULE
setting. The
default is a pricing module that always prices everything to be free.
The base distribution contains shuup.customer_group_pricing
, which is an
useful pricing module for many cases.
To acquire an instance of the current pricing module, use
get_pricing_module
.
In brief, a pricing module is able to price a product based on a
context; what exactly a context contains is determined by the module
in question. You can construct a context from a request by calling the
module’s get_context_from_request
method, or
for more advanced uses, when you do not have access to an HTTP request,
get_context_from_data
.
After you have acquired the module and a context, you can calculate
prices for a product with the module’s
get_price_info
method.
(Product
objects contain the
convenience methods
get_price_info
,
get_price
,
and get_base_price
which do these steps for you.)
If you have multiple products, it will likely be more efficient –
depending on the implementation of the module – to use the
get_price_infos
method.
TODO: document the concepts of base price and the pricing steps API. TODO: caching.
- class shuup.core.pricing.DiscountModule
Bases:
object
- abstractmethod discount_price(context: PricingContext, product: Product | int, price_info: PriceInfo) PriceInfo [source]
Discount given price of given product. :param context: Pricing context to operate in :param product: Product in question or its id :param price_info: Price to discount :return: A new instance of a discounted price
- discount_prices(context: PricingContext, products: Iterable[Product | int], price_infos: Dict[int, PriceInfo]) Dict[int, PriceInfo] [source]
Discount a bunch of prices.
- Parameters:
context (shuup.core.pricing.PricingContext) – Pricing context to operate in
products (Iterable[shuup.core.models.Product|int]) – Products in question or their ids
- Return type:
- get_pricing_steps(context: PricingContext, product: Product | int, steps: Iterable[PriceInfo]) Iterable[PriceInfo] [source]
Get discounted pricing steps for given product.
Base class version just discounts all the given steps with
discount_price
, but another module could add more steps and should do so, if the module introduces any pricing steps.- Parameters:
context (shuup.core.pricing.PricingContext) – Pricing context to operate in
product (shuup.core.models.Product|int) – Product in question or its id
- Return type:
- get_pricing_steps_for_products(context: PricingContext, products: Iterable[Product | int], steps: Iterable[PriceInfo]) Dict[int, Iterable[PriceInfo]] [source]
Get discounted pricing steps for a bunch of products.
- Parameters:
context (shuup.core.pricing.PricingContext) – Pricing context to operate in
products (Iterable[shuup.core.models.Product|int]) – Products in question or their ids
- Return type:
- index_shop_product(shop_product: ShopProduct | int, **kwargs)[source]
Index the shop product discounts
- shuup.core.pricing.get_discount_modules()
Get a list of configured discount module instances.
- Return type:
- shuup.core.pricing.get_price_info(context, product, quantity=1)
Get price info of product for given quantity.
Returned
PriceInfo
object contains calculatedprice
andbase_price
. The calculation of prices is handled in the current pricing module and possibly configured discount modules.- Parameters:
product (shuup.core.models.Product|int) –
Product
object or id ofProduct
- Return type:
- shuup.core.pricing.get_price_infos(context, products, quantity=1)
Get PriceInfo objects for a bunch of products.
Returns a dict with product id as key and PriceInfo as value.
May be faster than doing
get_price_info
for each product.- Parameters:
products (Iterable[shuup.core.models.Product|int]) – List of product objects or id’s
- Return type:
- shuup.core.pricing.get_pricing_module()
- Return type:
- shuup.core.pricing.get_pricing_steps(context, product)
Get context-specific list pricing steps for the given product.
Returns a list of PriceInfos, see
PricingModule.get_pricing_steps
for description of its format.- Parameters:
product (shuup.core.models.Product|int) – Product or product id
- Return type:
- shuup.core.pricing.get_pricing_steps_for_products(context, products)
Get pricing steps for a bunch of products.
Returns a dict with product id as key and step data (as list of PriceInfos) as values.
May be faster than doing
get_pricing_steps
for each product separately.
- class shuup.core.pricing.Price(value='0', *args, **kwargs)
Bases:
Money
Money amount with taxful/taxless info.
Taxful and taxless prices cannot be mixed in comparison or in calculations, i.e. operations like
x < y
orx + y
for two Pricesx
andy
withx.includes_tax != y.includes_tax
will raise anUnitMixupError
.In addition to
includes_tax
info, Prices are Money and know theirvalue
andcurrency
. To get the bare Money amount of aPrice
, use theamount
property.Create new Money instance with given value and currency.
If no currency is given explicitly and
value
has a property namedcurrency
, then that will be used. Otherwise currency is a required argument and not passing one will raise a TypeError.- Parameters:
value (str|numbers.Number) – Value as string or number.
currency (str|None) – Currency as ISO-4217 code (3-letter string) or None.
- includes_tax = None
- class shuup.core.pricing.PriceDisplayOptions(include_taxes=None, show_prices=True)
Bases:
object
Price display options.
Parameters on how prices should be rendered.
Initialize price display options.
- Parameters:
- property hide_prices
- class shuup.core.pricing.Priceful
Bases:
object
Mixin to define price properties based on other price properties.
You must provide at least
quantity
(Decimal
)
and both
or both
You may also provide
tax_amount
(Money
)
to get various tax related properties.
Provided
base_unit_price
,discount_amount
,price
,base_price
, andtax_amount
must have compatible units (i.e. same taxness and currency).- Invariants:
price = base_unit_price * quantity - discount_amount
discount_amount = base_price - price
discount_rate = 1 - (price / base_price)
discount_percentage = 100 * discount_rate
unit_discount_amount = discount_amount / quantity
taxful_price = raw_taxless_price + tax_amount
tax_rate = (raw_taxful_price.amount / raw_taxless_price.amount) - 1
tax_percentage = 100 * tax_rate
- property base_price
Total price for the specified quantity excluding discount.
- Return type:
- property base_unit_price
Undiscounted unit price.
Note: If quantity is 0, will return
base_price
.- Return type:
- property discount_amount
Amount of discount for the total quantity.
Normally positive or zero, but might also be negative if product is being sold with higher price than its normal price.
- Return type:
- property discount_percentage
Discount percentage, 100 meaning totally discounted.
See
discount_rate
.- Return type:
- property discount_rate
Discount rate, 1 meaning totally discounted.
Note: Could be negative, when base price is smaller than effective price. Could also be greater than 1, when effective price is negative.
If base price is 0, will return 0.
- Return type:
- property discounted_unit_price
Unit price with discount.
If quantity is 0, will return
base_unit_price - discount_amount
.- Return type:
- property is_discounted
Check if there is a discount in effect.
- Returns:
True, iff price < base price.
- property price
Total price for the specified quantity with discount.
For scenarios like below quantize the returned price.
base_unit_price * quantity - discount_amount 940.234529877 EUR (excl. tax) 1.000000000 0E-9 EUR (excl. tax) return 40.234529877000000000 EUR (excl. tax)
- Return type:
- property raw_taxful_price
- property raw_taxless_price
- property tax_percentage
decimal.Decimal
- Type:
rtype
- property tax_rate
decimal.Decimal
- Type:
rtype
- taxful_base_price
Taxful
base_price
- taxful_base_unit_price
Taxful
base_unit_price
- taxful_discount_amount
Taxful
discount_amount
- taxful_discounted_unit_price
Taxful
discounted_unit_price
- property taxful_price
TaxfulPrice
- Type:
rtype
- taxful_unit_discount_amount
Taxful
unit_discount_amount
- taxless_base_price
Taxless
base_price
- taxless_base_unit_price
Taxless
base_unit_price
- taxless_discount_amount
Taxless
discount_amount
- taxless_discounted_unit_price
Taxless
discounted_unit_price
- property taxless_price
TaxlessPrice
- Type:
rtype
- taxless_unit_discount_amount
Taxless
unit_discount_amount
- property unit_discount_amount
Discount amount per unit.
If quantity is 0, will return
discount_amount
.- Return type:
- class shuup.core.pricing.PriceInfo(price, base_price, quantity, expires_on=None)
Bases:
Priceful
Object for passing around pricing data of an item.
Initialize PriceInfo with prices and other parameters.
Prices can be taxful or taxless, but their types must match.
- Parameters:
price (Price) – Effective price for the specified quantity.
base_price (Price) – Base price for the specified quantity. Discounts are calculated based on this.
quantity (numbers.Number) – Quantity that the given price is for. Unit price is calculated by
discounted_unit_price = price / quantity
. Note: Quantity could be non-integral (i.e. decimal).expires_on (numbers.Number|None) – Unix timestamp, comparable to values returned by
time.time
, determining the point in time when the prices are no longer valid, or None if no expire time is set (which could mean indefinitely, but in reality, it just means undefined).
- __init__(price, base_price, quantity, expires_on=None)[source]
Initialize PriceInfo with prices and other parameters.
Prices can be taxful or taxless, but their types must match.
- Parameters:
price (Price) – Effective price for the specified quantity.
base_price (Price) – Base price for the specified quantity. Discounts are calculated based on this.
quantity (numbers.Number) – Quantity that the given price is for. Unit price is calculated by
discounted_unit_price = price / quantity
. Note: Quantity could be non-integral (i.e. decimal).expires_on (numbers.Number|None) – Unix timestamp, comparable to values returned by
time.time
, determining the point in time when the prices are no longer valid, or None if no expire time is set (which could mean indefinitely, but in reality, it just means undefined).
- base_price = None
- expires_on = None
- price = None
- quantity = None
- class shuup.core.pricing.PricingContext(shop, customer, time=None, basket=None, supplier=None)
Bases:
PricingContextable
Context for pricing.
Initialize pricing context for shop and customer.
- class shuup.core.pricing.PricingContextable
Bases:
object
Object that is or can be converted to a pricing context.
Currently there exists two kind of
PricingContextable
objects:PricingContext`(and its subclasses) and `HttpRequest
.Note
Expression
isinstance(request, PricingContextable)
will return True for arequest
which isHttpRequest
, becauseHttpRequest
is registered as a subclass of this abstract base class.This abstract base class is just a helper to allow writing simpler type specifiers, since we want to allow passing
HttpRequest
as a pricing context even though it is not aPricingContext
.
- class shuup.core.pricing.PricingModule
Bases:
object
- get_context_from_data(shop, customer, time=None, **kwargs)[source]
Create pricing context from given arguments.
- Return type:
- get_context_from_request(request)[source]
Create pricing context from HTTP request.
This base class implementation does not use
request
at all.- Return type:
- abstractmethod get_price_info(context, product, quantity=1)[source]
Get price info for a given quantity of the product.
- Parameters:
product (shuup.core.models.Product|int) –
Product
object or id ofProduct
.- Return type:
- get_price_infos(context, products, quantity=1)[source]
Get PriceInfo objects for a bunch of products.
Returns a dict with product id as key and PriceInfo as value.
May be faster than doing
get_price_info
for each product separately, since inheriting class may override this.- Parameters:
products (Iterable[shuup.core.models.Product|int]) – List of
Product
objects or id’s- Return type:
- get_pricing_steps(context, product)[source]
Get context-specific list pricing steps for the given product.
Returns a list of PriceInfos
[pi0, pi1, pi2, ...]
where each PriceInfo object is at the border unit price change: unit price for0 <= quantity < pi1.quantity1
ispi0.discounted_unit_price
, and unit price forpi1.quantity <= quantity < pi2.quantity
ispi1.discounted_unit_price
, and so on.If there are “no steps”, the return value will be a list of single PriceInfo object with the constant price, i.e.
[price_info]
.- Parameters:
product (shuup.core.models.Product|int) –
Product
object or id ofProduct
.- Return type:
- get_pricing_steps_for_products(context, products)[source]
Get pricing steps for a bunch of products.
Returns a dict with product id as key and step data (as list of PriceInfos) as values.
May be faster than doing
get_pricing_steps
for each product separately, since inheriting class may override this.
- identifier = None
- index_shop_product(shop_product: ShopProduct | int, **kwargs)[source]
Index the prices for the given shop product
- name = None
- pricing_context_class
alias of
PricingContext
- class shuup.core.pricing.TaxfulPrice(value='0', *args, **kwargs)
Bases:
Price
Price which includes taxes.
Check the base class,
Price
, for more info.Create new Money instance with given value and currency.
If no currency is given explicitly and
value
has a property namedcurrency
, then that will be used. Otherwise currency is a required argument and not passing one will raise a TypeError.- Parameters:
value (str|numbers.Number) – Value as string or number.
currency (str|None) – Currency as ISO-4217 code (3-letter string) or None.
- includes_tax = True
- class shuup.core.pricing.TaxlessPrice(value='0', *args, **kwargs)
Bases:
Price
Price which does not include taxes.
Check the base class,
Price
, for more info.Create new Money instance with given value and currency.
If no currency is given explicitly and
value
has a property namedcurrency
, then that will be used. Otherwise currency is a required argument and not passing one will raise a TypeError.- Parameters:
value (str|numbers.Number) – Value as string or number.
currency (str|None) – Currency as ISO-4217 code (3-letter string) or None.
- includes_tax = False