Shop¶
-
class
plata.shop.models.
BillingShippingAddress
(*args, **kwargs)[source] Abstract base class for all models storing a billing and a shipping address
-
addresses
()[source] Return a
dict
containing a billing and a shipping address, taking into account the value of theshipping_same_as_billing
flag
-
-
class
plata.shop.models.
Order
(*args, **kwargs)[source] The main order model. Used for carts and orders alike.
-
CART
= 10 Order object is a cart.
-
CHECKOUT
= 20 Checkout process has started.
-
COMPLETED
= 50 Order has been completed. Plata itself never sets this state, it is only meant for use by the shop owners.
-
CONFIRMED
= 30 Order has been confirmed, but it not (completely) paid for yet.
-
exception
DoesNotExist
-
exception
MultipleObjectsReturned
-
PAID
= 40 Order has been completely paid for.
-
PENDING
= 35 For invoice payment methods, when waiting for the money
-
VALIDATE_ALL
= 100 This should not be used while registering a validator, it’s mostly useful as an argument to
validate()
when you want to run all validators.
-
VALIDATE_BASE
= 10 This validator is always called; basic consistency checks such as whether the currencies in the order match should be added here.
-
VALIDATE_CART
= 20 A cart which fails the criteria added to the
VALIDATE_CART
group isn’t considered a valid cart and the user cannot proceed to the checkout form. Stuff such as stock checking, minimal order total checking, or maximal items checking might be added here.
-
balance_remaining
Returns the balance which needs to be paid by the customer to fully pay this order. This value is not necessarily the same as the order total, because there can be more than one order payment in principle.
-
discount
Returns the discount total.
-
discount_remaining
Remaining discount amount excl. tax
-
is_confirmed
()[source] Returns
True
if this order has already been confirmed and therefore cannot be modified anymore.
-
items_in_order
()[source] Returns the item count in the order
This is different from
order.items.count()
because it counts items, not distinct products.
-
modify_item
(product, relative=None, absolute=None, recalculate=True, data=None, item=None, force_new=False)[source] Updates order with the given product
relative
orabsolute
: Add/subtract or define order item amount exactlyrecalculate
: Recalculate order after cart modification (defaults toTrue
)data
: Additional data for the order item; replaces the contents of the JSON field if it is notNone
. Pass an empty dictionary if you want to reset the contents.item
: The order item which should be modified. Will be automatically detected using the product if unspecified.force_new
: Force the creation of a new order item, even if the product exists already in the cart (especially useful if the product is configurable).
Returns the
OrderItem
instance; if quantity is zero, the order item instance is deleted, thepk
attribute set toNone
but the order item is returned anyway.
-
order_id
Returns
_order_id
(if it has been set) or a generic ID for this order.
-
recalculate_total
(save=True)[source] Recalculates totals, discounts, taxes.
-
classmethod
register_validator
(validator, group)[source] Registers another order validator in a validation group
A validator is a callable accepting an order (and only an order).
There are several types of order validators:
- Base validators are always called
- Cart validators: Need to validate for a valid cart
- Checkout validators: Need to validate in the checkout process
-
reload
()[source] Return this order instance, reloaded from the database
Used f.e. inside the payment processors when adding new payment records etc.
-
save
(*args, **kwargs)[source] Sequential order IDs for completed orders.
-
shipping
Returns the shipping cost, with or without tax depending on this order’s
price_includes_tax
field.
-
subtotal
Returns the order subtotal.
-
tax
Returns the tax total for this order, meaning tax on order items and tax on shipping.
-
update_status
(status, notes)[source] Update the order status
-
validate
(group)[source] Validates this order
The argument determines which order validators are called:
Order.VALIDATE_BASE
Order.VALIDATE_CART
Order.VALIDATE_CHECKOUT
Order.VALIDATE_ALL
-
-
class
plata.shop.models.
OrderItem
(*args, **kwargs)[source] Single order line item
-
exception
DoesNotExist
-
exception
MultipleObjectsReturned
-
exception
-
class
plata.shop.models.
OrderPayment
(*args, **kwargs)[source] Order payment
Stores additional data from the payment interface for analysis and accountability.
-
exception
DoesNotExist
-
exception
MultipleObjectsReturned
-
exception
-
class
plata.shop.models.
OrderStatus
(*args, **kwargs)[source] Order status
Stored in separate model so that the order status changes stay visible for analysis after the fact.
-
exception
DoesNotExist
-
exception
MultipleObjectsReturned
-
exception
-
class
plata.shop.models.
PriceBase
(*args, **kwargs)[source] Price for a given product, currency, tax class and time period
Prices should not be changed or deleted but replaced by more recent prices. (Deleting old prices does not hurt, but the price history cannot be reconstructed anymore if you’d need it.)
The concrete implementation needs to provide a foreign key to the product model.
-
handle_order_item
(item)[source] Set price data on the
OrderItem
passed
-
-
class
plata.shop.models.
TaxClass
(*args, **kwargs)[source] Tax class, storing a tax rate
TODO informational / advisory currency or country fields?
-
exception
DoesNotExist
-
exception
MultipleObjectsReturned
-
exception
-
plata.shop.models.
validate_order_currencies
(order)[source] Check whether order contains more than one or an invalid currency
Order processors¶
-
class
plata.shop.processors.
ApplyRemainingDiscountToShippingProcessor
(shared_state)[source] Apply the remaining discount to the shipping (if shipping is non-zero and there are any remaining discounts left)
-
class
plata.shop.processors.
DiscountProcessor
(shared_state)[source] Apply all discounts which do not act as a means of payment but instead act on the subtotal
-
class
plata.shop.processors.
FixedAmountShippingProcessor
(shared_state)[source] Set shipping costs to a fixed value. Uses
PLATA_SHIPPING_FIXEDAMOUNT
. If you have differing needs you should probably implement your own shipping processor (and propose it for inclusion if you like) instead of extending this one.PLATA_SHIPPING_FIXEDAMOUNT = { 'cost': Decimal('8.00'), 'tax': Decimal('19.6'), }
-
class
plata.shop.processors.
InitializeOrderProcessor
(shared_state)[source] Zero out all relevant order values and calculate line item prices excl. tax.
-
class
plata.shop.processors.
ItemSummationProcessor
(shared_state)[source] Sum up line item prices, discounts and taxes.
-
class
plata.shop.processors.
MeansOfPaymentDiscountProcessor
(shared_state)[source] Apply all discounts which act as a means of payment.
-
class
plata.shop.processors.
OrderSummationProcessor
(shared_state)[source] Sum up order total by adding up items and shipping totals.
-
process
(order, items)[source] The value must be quantized here, because otherwise f.e. the payment modules will be susceptible to rounding errors giving f.e. missing payments of 0.01 units.
-
-
class
plata.shop.processors.
ProcessorBase
(shared_state)[source] Order processor class base. Offers helper methods for order total aggregation and tax calculation.
-
add_tax_details
(tax_details, tax_rate, price, discount, tax_amount)[source] Add tax details grouped by tax_rate. Especially useful if orders potentially use more than one tax class. These values are not used for the order total calculation – they are only needed to show the tax amount for different tax rates if this is necessary for your invoices.
tax_details
: The tax details dict, most often stored asorder.data['tax_details'] = tax_details.items()
tax_rate
: The tax rate of the current entryprice
: The price excl. taxdiscount
: The discount amount (will be subtracted from the price before applying the tax)tax_amount
: The exact amount; a bit redundant because this could be calculated using the values above as well
See the taxes documentation or the standard invoice PDF generation code if you need to know more about the use of these values.
-
process
(order, items)[source] This is the method which must be implemented in order processor classes.
-
split_cost
(cost_incl_tax, tax_rate)[source] Split a cost incl. tax into the part excl. tax and the tax
-
-
class
plata.shop.processors.
TaxProcessor
(shared_state)[source] Calculate taxes for every line item and aggregate tax details.
-
class
plata.shop.processors.
ZeroShippingProcessor
(shared_state)[source] Set shipping costs to zero.
Template tags¶
-
plata.shop.templatetags.plata_tags.
form_errors
(parser, token)[source] Show all form and formset errors:
{% form_errors form formset1 formset2 %}
Silently ignores non-existant variables.
-
plata.shop.templatetags.plata_tags.
form_item
(item, additional_classes=None)[source] Helper for easy displaying of form items:
{% for field in form %}{% form_item field %}{% endfor %}
-
plata.shop.templatetags.plata_tags.
form_item_plain
(item, additional_classes=None)[source] Helper for easy displaying of form items without any additional tags (table cells or paragraphs) or labels:
{% form_item_plain field %}
-
plata.shop.templatetags.plata_tags.
form_items
(form)[source] Render all form items:
{% form_items form %}
-
plata.shop.templatetags.plata_tags.
load_plata_context
(context)[source] Conditionally run plata’s context processor using {% load_plata_context %}
Rather than having the overheads involved in globally adding it to TEMPLATE_CONTEXT_PROCESSORS.
-
plata.shop.templatetags.plata_tags.
quantity_ordered
(product, order)[source] e.g. {% if product|quantity_ordered:plata.order > 0 %} … {% endif %}
Signals¶
-
plata.shop.signals.
contact_created
= <django.dispatch.dispatcher.Signal object> Emitted upon contact creation. Receives the user and contact instance and the new password in cleartext.
-
plata.shop.signals.
order_confirmed
= <django.dispatch.dispatcher.Signal object> Emitted upon order confirmation. Receives an order instance.
-
plata.shop.signals.
order_paid
= <django.dispatch.dispatcher.Signal object> Emitted when an order has been completely paid for. Receives the order and payment instances and the remaining discount amount excl. tax, if there is any.
Notifications¶
Even though these shop signal handlers might be useful, you might be better off writing your own handlers for the three important signals:
contact_created
: A new contact has been created during the checkout processorder_confirmed
: The order has been confirmed, a payment method has been selectedorder_paid
: The order is fully paid
A real-world example follows:
from django.utils.translation import activate
from plata.shop import notifications, signals as shop_signals
class EmailHandler(notifications.BaseHandler):
ALWAYS = ['shopadmin@example.com']
SHIPPING = ['warehouse@example.com']
def __call__(self, sender, order, **kwargs):
cash_on_delivery = False
try:
if (order.payments.all()[0].payment_module_key == 'cod'):
cash_on_delivery = True
except:
pass
if order.language_code:
activate(order.language_code)
invoice_message = self.create_email_message(
'plata/notifications/order_paid.txt',
order=order,
**kwargs)
invoice_message.attach(order.order_id + '.pdf',
self.invoice_pdf(order), 'application/pdf')
invoice_message.to.append(order.email)
invoice_message.bcc.extend(self.ALWAYS)
packing_slip_message = self.create_email_message(
'plata/notifications/packing_slip.txt',
order=order,
**kwargs)
packing_slip_message.attach(
order.order_id + '-LS.pdf',
self.packing_slip_pdf(order),
'application/pdf')
packing_slip_message.to.extend(self.ALWAYS)
if cash_on_delivery:
invoice_message.bcc.extend(self.SHIPPING)
else:
packing_slip_message.to.extend(self.SHIPPING)
invoice_message.send()
packing_slip_message.send()
shop_signals.contact_created.connect(
notifications.ContactCreatedHandler(),
weak=False)
shop_signals.order_paid.connect(
EmailHandler(),
weak=False)
-
class
plata.shop.notifications.
ContactCreatedHandler
(always_to=None, always_bcc=None)[source] Send an e-mail message to a newly created contact, optionally BCC’ing the addresses passed as
always_bcc
upon handler initialization.Usage:
signals.contact_created.connect( ContactCreatedHandler(), weak=False)
or:
signals.contact_created.connect( ContactCreatedHandler(always_bcc=['owner@example.com']), weak=False)
-
class
plata.shop.notifications.
SendInvoiceHandler
(always_to=None, always_bcc=None)[source] Send an e-mail with attached invoice to the customer after successful order completion, optionally BCC’ing the addresses passed as
always_bcc
to the handler upon initialization.Usage:
signals.order_paid.connect( SendInvoiceHandler(always_bcc=['owner@example.com']), weak=False)
-
class
plata.shop.notifications.
SendPackingSlipHandler
(always_to=None, always_bcc=None)[source] Send an e-mail with attached packing slip to the addresses specified upon handler initialization. You should pass at least one address in either the
always_to
or thealways_bcc
argument, or else the e-mail will go nowhere.Usage:
signals.order_paid.connect( SendPackingSlipHandler(always_to=['warehouse@example.com']), weak=False)