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'
get_price_info(context, product, quantity=1)[source]

Return a PriceInfo calculated from ShopProduct.default_price

Since ShopProduct.default_price can be None it will be set to zero (0) if None.

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:
Return type:

dict[int,PriceInfo]

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:
Return type:

list[PriceInfo]

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:
Return type:

dict[int,list[PriceInfo]]

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:

list[DiscountModule]

shuup.core.pricing.get_price_info(context, product, quantity=1)

Get price info of product for given quantity.

Returned PriceInfo object contains calculated price and base_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 of Product

Return type:

shuup.core.pricing.PriceInfo

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:

dict[int,PriceInfo]

shuup.core.pricing.get_pricing_module()
Return type:

shuup.core.pricing.PricingModule

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:

list[shuup.core.pricing.PriceInfo]

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.

Parameters:

products (Iterable[shuup.core.models.Product|int]) – List of product objects or id’s

Return type:

dict[int,list[PriceInfo]]

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 or x + y for two Prices x and y with x.includes_tax != y.includes_tax will raise an UnitMixupError.

In addition to includes_tax info, Prices are Money and know their value and currency. To get the bare Money amount of a Price, use the amount property.

Create new Money instance with given value and currency.

If no currency is given explicitly and value has a property named currency, 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.

property amount

Money amount of this price.

Return type:

Money

classmethod from_data(value, currency, includes_tax=None)[source]
includes_tax = None
unit_matches_with(other)[source]

Test if self and other have matching units.

Return type:

bool

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:
  • include_taxes (bool|None) – Whether include taxes to rendered prices or not. If None, show prices in their original taxness.

  • show_prices (bool) – Whether show prices at all.

__init__(include_taxes=None, show_prices=True)[source]

Initialize price display options.

Parameters:
  • include_taxes (bool|None) – Whether include taxes to rendered prices or not. If None, show prices in their original taxness.

  • show_prices (bool) – Whether show prices at all.

classmethod from_context(context)[source]

Get price display options from context.

Return type:

PriceDisplayOptions

property hide_prices
set_for_request(request)[source]

Set price display options of given request to self.

class shuup.core.pricing.Priceful

Bases: object

Mixin to define price properties based on other price properties.

You must provide at least

and both

  • base_unit_price (Price) and

  • discount_amount (Price)

or both

You may also provide

to get various tax related properties.

Provided base_unit_price, discount_amount, price, base_price, and tax_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:

shuup.core.pricing.Price

property base_unit_price

Undiscounted unit price.

Note: If quantity is 0, will return base_price.

Return type:

shuup.core.pricing.Price

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:

shuup.core.pricing.Price

property discount_percentage

Discount percentage, 100 meaning totally discounted.

See discount_rate.

Return type:

decimal.Decimal

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:

decimal.Decimal

property discounted_unit_price

Unit price with discount.

If quantity is 0, will return base_unit_price - discount_amount.

Return type:

shuup.core.pricing.Price

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:

shuup.core.pricing.Price

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:

shuup.core.pricing.Price

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.

__init__(shop, customer, time=None, basket=None, supplier=None)[source]

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 a request which is HttpRequest, because HttpRequest 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 a PricingContext.

class shuup.core.pricing.PricingModule

Bases: object

get_context(context)[source]

Create pricing context from pricing contextable object.

Return type:

PricingContext

get_context_from_data(shop, customer, time=None, **kwargs)[source]

Create pricing context from given arguments.

Return type:

PricingContext

get_context_from_request(request)[source]

Create pricing context from HTTP request.

This base class implementation does not use request at all.

Return type:

PricingContext

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 of Product.

Return type:

PriceInfo

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:

dict[int,PriceInfo]

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 for 0 <= quantity < pi1.quantity1 is pi0.discounted_unit_price, and unit price for pi1.quantity <= quantity < pi2.quantity is pi1.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 of Product.

Return type:

list[PriceInfo]

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.

Parameters:

products (Iterable[shuup.core.models.Product|int]) – List of Product objects or id’s.

Return type:

dict[int,list[PriceInfo]]

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 named currency, 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 named currency, 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