diff --git a/.coveragerc b/.coveragerc
index 5bacb50098f..fa7122d2efe 100644
--- a/.coveragerc
+++ b/.coveragerc
@@ -1,2 +1,3 @@
[run]
source = oscar
+omit = *migrations*
diff --git a/.gitignore b/.gitignore
index 6afcde0ece8..ee161e8dbd3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,8 +1,8 @@
# Packaging
*.pyc
*.egg-info
-dist/
-build/
+/dist/
+/build/
# Vagrant
.vagrant
@@ -21,26 +21,28 @@ build/
.idea
# Docs
-docs/build/*
+/docs/build/*
*.pdf
TODO
# Test files
.coverage
+.noseids
coverage.xml
violations.txt
nosetests.xml
-htmlcov/*
-.tox/*
+/htmlcov/*
+/.tox/*
# Example sites
settings_local.py
-sites/sandbox/*.sqlite
-sites/sandbox/assets/
-sites/sandbox/public/
-sites/sandbox/whoosh_index/
-sites/sandbox/logs/
-sites/demo/*.sqlite
-sites/demo/assets/
-sites/demo/public/
-sites/demo/whoosh_index/
+/sites/sandbox/*.sqlite
+/sites/sandbox/assets/
+/sites/sandbox/public/
+/sites/sandbox/whoosh_index/
+/sites/sandbox/logs/
+/sites/demo/*.sqlite
+/sites/demo/assets/
+/sites/demo/public/
+/sites/demo/whoosh_index/
+/sites/demo/logs/
diff --git a/.mailmap b/.mailmap
new file mode 100644
index 00000000000..0ac5e3165a8
--- /dev/null
+++ b/.mailmap
@@ -0,0 +1,11 @@
+Andrew Ingram AndrewIngram
+Sebastian Vetter Sebastian Vetter Sebastian Vetter
+Andy Sellick Andy Sellick
+Patryk Zawadzki Patryk Zawadzki
+John Papanastasiou John Papanastasiou
+Jonathan Moss Jonathan Moss
+Kura Kura
+Mohammad Abbas Mohammad Abbas Mohammad Abbas
+Oliver Randell OliverRandell
+Paweł Kowalski Paweł Kowalski
+Łukasz Lechowicz Łukasz Lechowicz
diff --git a/.travis.yml b/.travis.yml
index d1e24f2adfe..5c28d2bdcef 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,14 +1,21 @@
language: python
python:
- - 2.6
- - 2.7
+- '2.6'
+- '2.7'
env:
-# NOTE: easy_install *will* downgrade if setup.py specifies a max version
-# This leads to seemingly passing tests
- - DJANGO_VERSION=1.4.5
-install:
- - easy_install Django==$DJANGO_VERSION
+ global:
+ # $TRANSIFEX_PASSWORD for oscar_bot (used in transifex.sh)
+ secure: FuIlzEsGJiAwhaIRBmRNsq9eXmuzs25fX6BChknW4lDyVAySWMp0+Zps9Bd0JgfFYUG3Ip+OTmksYIoTUsG25ZJS9cq1IFt3QKUAN70YCI/4ZBLeIdICPEyxq+Km179+NeEXmBUug17RLMLxh3MWfO+RKUHK9yHIPNNpq0dNyoo=
+ matrix:
+ - DJANGO_VERSION=1.4.10
+ - DJANGO_VERSION=1.5.5
+install:
+- easy_install Django==$DJANGO_VERSION
+before_script:
+ - mysql -e 'create database oscar_vagrant;'
+ - psql -c 'create database oscar_vagrant;' -U postgres
script:
- - make travis
+- make travis
after_success:
- - coveralls
+- coveralls
+- ./transifex.sh
diff --git a/AUTHORS b/AUTHORS
index 685f5f1ad94..4936a886235 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -1,11 +1,18 @@
-The PRIMARY AUTHORS are:
-
-* David Winterbottom
-* Andrew Ingram
-* Sebastian Vetter
-
-Significant contributions from:
-
-* Patryk Zawadzki
-* Tomasz Rybarczyk
-* Janusz Harkot
+David Winterbottom
+Sebastian Vetter
+Andrew Ingram
+Jon Price
+Maik Hoepfel
+Asia Biega
+Andy Sellick
+Tomasz Rybarczyk
+Eleni Lixourioti
+OliverRandell
+Kura
+Paweł Kowalski
+Dawid Lorenz
+Pavel Vavruska
+Jonathan Moss
+Janusz Harkot
+Patryk Zawadzki
+AndrewIngram
diff --git a/CHANGELOG.rst b/CHANGELOG.rst
index efc0fd5855c..d713fdfe099 100644
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -4,6 +4,67 @@ Changelog
For releases after 0.4, see the release notes in the docs.
+0.4.11 - 2013-08-08
+-------------------
+
+Add extra blocks to order dashboard template.
+
+0.4.10 - 2013-07-03
+-------------------
+
+Extend range of bankcard expiry month field.
+
+0.4.9 - 2013-04-17
+------------------
+
+Make ``AbstractStockRecord`` abstract (`#645`)
+
+.. _`#645`: https://github.com/tangentlabs/django-oscar/pull/645
+
+0.4.8 - 2013-04-08
+------------------
+
+Fix bug with order dashboard line editing (`#622`_)
+
+.. _`#622`: https://github.com/tangentlabs/django-oscar/pull/622
+
+0.4.7 - 2013-03-20
+------------------
+
+Fix bug with order dashboard searching (`#587`_)
+
+.. _`#587`: https://github.com/tangentlabs/django-oscar/pull/587
+
+0.4.6 - 2013-03-05
+------------------
+
+Fix dependencies in ``setup.py``
+
+0.4.4 - 2013-01-25
+------------------
+
+Extend ``get_class`` to support loading from non-Oscar packages
+
+0.4.4 - 2013-01-16
+------------------
+
+Correct django-haystack in setup.py
+
+0.4.3 - 2013-01-16
+------------------
+
+Pin django-haystack version as backwards-incompatiable changes are happening
+
+0.4.2 - 2012-12-14
+------------------
+
+Nano-release to fix logout redirect bug
+
+0.4.1 - 2012-12-06
+------------------
+
+Nano-release to bump dependency versions.
+
0.4 - 2012-10-19
----------------
@@ -53,6 +114,29 @@ changes.
Please ask on the mailing list if any other problems are encountered.
+0.3.7 - 2013-07-03
+------------------
+* Extend number of years in bankcard expiry field
+
+0.3.6 - 2013-04-08
+-------------------
+* Fix line-handling bug in order dashboard.
+
+0.3.5 - 2012-09-28
+------------------
+A couple of minor adjustments for Tangent projects
+
+* Add handling of custom redirect after adding to basket
+* Add recursive URL decoration
+
+0.3.4 - 2012-09-24
+------------------
+
+* Rework price lookups in offer calculations (backport of functionality from 0.4)
+* Add additional block to profile template
+
+Diff: https://github.com/tangentlabs/django-oscar/compare/0.3.3...0.3.4
+
0.3.3 - 2012-08-24
-------------------
@@ -111,6 +195,11 @@ instead of::
# base.html
{% extends 'templates/base.html' %}
+0.2.2 - 13 July 2012
+~~~~~~~~~~~~~~~~~~~~
+
+Fixes a bug with applying absolute-discount benefits
+
0.2.1 - 09 July 2012
--------------------
diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst
old mode 100755
new mode 100644
diff --git a/MANIFEST.in b/MANIFEST.in
index f1f19f30018..5d4e558ade7 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -1,6 +1,8 @@
include *.rst
+include AUTHORS
+include LICENSE
recursive-include oscar/templates *.txt *.html
recursive-include oscar/apps *.json
recursive-include oscar/fixtures *.json
recursive-include oscar/static *
-recursive-include oscar/locale *.po
+recursive-include oscar/locale *.po *.mo
diff --git a/Makefile b/Makefile
index 9bdc392af39..6b197f3d576 100644
--- a/Makefile
+++ b/Makefile
@@ -2,7 +2,7 @@
.PHONY: install upgrade sandbox demo coverage ci i18n lint travis docs
install:
- pip install -r requirements.txt --use-mirrors
+ pip install -r requirements.txt
python setup.py develop
upgrade:
@@ -15,27 +15,42 @@ sandbox: install
sites/sandbox/manage.py syncdb --noinput
sites/sandbox/manage.py migrate
# Import some fixtures
- sites/sandbox/manage.py oscar_import_catalogue sites/_fixtures/books-catalogue.csv
- sites/sandbox/manage.py oscar_import_catalogue_images sites/_fixtures/books-images.tar.gz
+ sites/sandbox/manage.py oscar_import_catalogue sites/sandbox/fixtures/*.csv
+ sites/sandbox/manage.py oscar_import_catalogue_images sites/sandbox/fixtures/images.tar.gz
sites/sandbox/manage.py loaddata countries.json sites/_fixtures/pages.json sites/_fixtures/auth.json sites/_fixtures/ranges.json sites/_fixtures/offers.json
- sites/sandbox/manage.py rebuild_index --noinput
+ sites/sandbox/manage.py clear_index --noinput
+ sites/sandbox/manage.py update_index catalogue
+
+geoip:
+ wget http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz
+ gunzip GeoLiteCity.dat.gz
+ mv GeoLiteCity.dat sites/demo/geoip
demo: install
- -rm -f sites/demo/db.sqlite
+ # Install additional requirements
+ pip install -r requirements_demo.txt
# Create database
+ sites/demo/manage.py reset_db --router=default --noinput
sites/demo/manage.py syncdb --noinput
sites/demo/manage.py migrate
- # Import some fixtures
- sites/demo/manage.py oscar_import_catalogue sites/_fixtures/books-catalogue.csv
- sites/demo/manage.py oscar_import_catalogue_images sites/_fixtures/books-images.tar.gz
- sites/demo/manage.py loaddata countries.json sites/_fixtures/pages.json sites/_fixtures/auth.json sites/_fixtures/ranges.json
- sites/demo/manage.py rebuild_index --noinput
+ # Import some core fixtures
+ sites/demo/manage.py loaddata countries.json sites/_fixtures/pages.json
+ # Create catalogue (create product classes from fixture than import CSV files)
+ sites/demo/manage.py loaddata sites/demo/fixtures/auth.json sites/demo/fixtures/offers.json
+ sites/demo/manage.py loaddata sites/demo/fixtures/product-classes.json sites/demo/fixtures/product-attributes.json sites/demo/fixtures/shipping-event-types.json
+ sites/demo/manage.py create_products --class=Books sites/demo/fixtures/books.csv
+ sites/demo/manage.py create_products --class=Downloads sites/demo/fixtures/downloads.csv
+ sites/demo/manage.py create_products --class=Clothing sites/demo/fixtures/clothing.csv
+ sites/demo/manage.py import_product_images sites/demo/fixtures/images/
+ # Update search index
+ sites/demo/manage.py clear_index --noinput
+ sites/demo/manage.py update_index catalogue
docs:
cd docs && make html
coverage:
- coverage run ./runtests.py
+ coverage run ./runtests.py --with-xunit
coverage xml -i
# We probably should use upgrade instead of install here but we have a conflict
@@ -51,6 +66,8 @@ lint:
# and upgrade would overwrite it. We also build the sandbox as part of this target
# to catch any errors that might come from that build process.
travis: install lint coverage sandbox
+ pip install -r requirements_vagrant.txt
+ cd sites/sandbox && ./test_migrations.sh
messages:
# Create the .po files used for i18n
@@ -62,12 +79,13 @@ compiledmessages:
puppet:
# Install puppet modules required to set-up a Vagrant box
+ mkdir -p sites/puppet/modules
rm -rf sites/puppet/modules/*
puppet module install --target-dir sites/puppet/modules/ saz-memcached -v 2.0.2
puppet module install --target-dir sites/puppet/modules/ puppetlabs/mysql
puppet module install --target-dir sites/puppet/modules/ puppetlabs/apache
git clone git://github.com/akumria/puppet-postgresql.git sites/puppet/modules/postgresql
- git clone git://github.com/uggedal/puppet-module-python.git sites/puppet/modules/python
+ git clone git://github.com/puppetmodules/puppet-module-python.git sites/puppet/modules/python
git clone git://github.com/codeinthehole/puppet-userconfig.git sites/puppet/modules/userconfig
css:
@@ -75,3 +93,13 @@ css:
lessc oscar/static/oscar/less/styles.less > oscar/static/oscar/css/styles.css
lessc oscar/static/oscar/less/responsive.less > oscar/static/oscar/css/responsive.css
lessc oscar/static/oscar/less/dashboard.less > oscar/static/oscar/css/dashboard.css
+
+demo_css:
+ # Compile CSS for demo site
+ lessc sites/demo/static/demo/less/styles.less > sites/demo/static/demo/css/styles.css
+ lessc sites/demo/static/demo/less/responsive.less > sites/demo/static/demo/css/responsive.css
+
+clean:
+ # Remove files not in source control
+ find . -type f -name "*.pyc" -delete
+ rm -rf nosetests.xml coverage.xml htmlcov *.egg-info *.pdf dist violations.txt
diff --git a/README.rst b/README.rst
index afbb64ea41c..133a85e8f9f 100644
--- a/README.rst
+++ b/README.rst
@@ -1,4 +1,5 @@
-.. image:: http://img692.imageshack.us/img692/6498/logovf.png
+.. image:: https://github.com/tangentlabs/django-oscar/raw/master/docs/images/logos/oscar.png
+ :target: http://oscarcommerce.com
===================================
Domain-driven e-commerce for Django
@@ -19,29 +20,42 @@ sites rich in domain-specific business logic.
Further reading:
* `Official homepage`_
+* `Demo site`_ (a reference build of an Oscar project)
* `Sandbox site`_ (an hourly build of the unstable master branch - it's
experimental but feel free to explore and get a feel for the base Oscar
- install. Polished demo site coming soon)
+ install.)
* `Documentation`_ on the excellent `readthedocs.org`_
* `Google Group`_ - the mailing list is django-oscar@googlegroups.com
* `Continuous integration homepage`_ on `travis-ci.org`_
* `Twitter account for news and updates`_
-* `Twitter account of all commits`_
* `crate.io page`_
* `PyPI page`_
* `Transifex project`_ - translating Oscar made easy
Continuous integration status:
-.. image:: https://secure.travis-ci.org/tangentlabs/django-oscar.png
+.. image:: https://secure.travis-ci.org/tangentlabs/django-oscar.png?branch=master
:target: http://travis-ci.org/#!/tangentlabs/django-oscar
.. image:: https://coveralls.io/repos/tangentlabs/django-oscar/badge.png?branch=master
:alt: Coverage
:target: https://coveralls.io/r/tangentlabs/django-oscar
+PyPI status:
+
+.. image:: https://pypip.in/v/django-oscar/badge.png
+ :target: https://crate.io/packages/django-oscar/
+
+.. image:: https://pypip.in/d/django-oscar/badge.png
+ :target: https://crate.io/packages/django-oscar/
+
+.. image:: https://d2weczhvl823v0.cloudfront.net/tangentlabs/django-oscar/trend.png
+ :alt: Bitdeli badge
+ :target: https://bitdeli.com/free
+
.. _`Official homepage`: http://oscarcommerce.com
.. _`Sandbox site`: http://latest.oscarcommerce.com
+.. _`Demo site`: http://demo.oscarcommerce.com
.. _`Documentation`: http://django-oscar.readthedocs.org/en/latest/
.. _`readthedocs.org`: http://readthedocs.org
.. _`Continuous integration homepage`: http://travis-ci.org/#!/tangentlabs/django-oscar
@@ -54,22 +68,21 @@ Continuous integration status:
.. _`Transifex project`: https://www.transifex.com/projects/p/django-oscar/
Oscar was written by `David Winterbottom`_ (`@codeinthehole`_) and is developed
-and maintained by `Tangent Labs`_, a London-based digital agency, with help from
-`Mirumee`_.
-
-.. _`Mirumee`: http://mirumee.com/
+and maintained by `Tangent Labs`_, a London-based digital agency.
.. _`David Winterbottom`: http://codeinthehole.com
.. _`@codeinthehole`: https://twitter.com/codeinthehole
.. _`Tangent Labs`: http://www.tangentlabs.co.uk
-.. _`Mirumee`: http://mirumee.com/
Screenshots
-----------
-These are a few screenshots from the 'sandbox' example site that ships with
-Oscar. It sports a simple design built with Twitter's Bootstrap_. It provides a
-good starting point for quickly building elegant e-commerce sites.
+Sandbox
+~~~~~~~
+
+These are screenshots from the 'sandbox' example site that ships with
+Oscar. It sports a simple design built with Twitter's Bootstrap_ and provides a
+good starting point for rapidly building elegant e-commerce sites.
.. _Bootstrap: http://twitter.github.com/bootstrap/
@@ -86,15 +99,33 @@ good starting point for quickly building elegant e-commerce sites.
:target: https://github.com/tangentlabs/django-oscar/raw/master/docs/images/screenshots/dashboard.png
The sandbox site is also available to browse at
-http://latest.oscarcommerce.com
+http://latest.oscarcommerce.com. Dashboard users can be created using `this
+gateway page`_.
-You can have this sample shop running on your machine `in 5 commands`_.
+The sandbox site can be set-up locally `in 5 commands`_. Want to
+make changes? Check out the `contributing guidelines`_.
+.. _`this gateway page`: http://latest.oscarcommerce.com/gateway/
.. _`in 5 commands`: http://django-oscar.readthedocs.org/en/latest/internals/sandbox.html#running-the-sandbox-locally
+.. _`contributing guidelines`: http://django-oscar.readthedocs.org/en/latest/internals/contributing/index.html
+
+Demo
+~~~~
-Want to make changes? Check out the `contributing guidelines`_.
+Oscar also ships with a demo site, which is a reference build of an Oscar
+project. It integrates with Oscar's stores_, PayPal_ and Datacash_ extensions.
-.. _`contributing guidelines`: http://django-oscar.readthedocs.org/en/latest/contributing/index.html
+.. image:: https://github.com/tangentlabs/django-oscar/raw/master/docs/images/screenshots/demo.home.thumb.png
+ :target: https://github.com/tangentlabs/django-oscar/raw/master/docs/images/screenshots/demo.home.png
+
+.. image:: https://github.com/tangentlabs/django-oscar/raw/master/docs/images/screenshots/demo.browse.thumb.png
+ :target: https://github.com/tangentlabs/django-oscar/raw/master/docs/images/screenshots/demo.browse.png
+
+The demo site is also available to browse at
+http://demo.oscarcommerce.com
+
+.. _stores: https://github.com/tangentlabs/django-oscar-stores
+.. _PayPal: https://github.com/tangentlabs/django-oscar-paypal
Extensions
----------
@@ -110,7 +141,10 @@ The following extensions are stable and ready for use:
functionality and loyalty schemes)
* django-oscar-stores_ - Physical stores integration (opening hours, store
locator etc)
-* django-oscar-testsupport_ - Testing utilities for Oscar extensions.
+* django-oscar-easyrec_ - Recomendations using EasyRec_
+ locator etc)
+* django-oscar-testsupport_ - Testing utilities for Oscar extensions
+ (deprecated)
.. _django-oscar-datacash: https://github.com/tangentlabs/django-oscar-datacash
.. _django-oscar-paymentexpress: https://github.com/tangentlabs/django-oscar-paymentexpress
@@ -125,22 +159,44 @@ The following extensions are stable and ready for use:
.. _Jirafe: https://jirafe.com/
.. _django-oscar-accounts: https://github.com/tangentlabs/django-oscar-accounts
.. _django-oscar-testsupport: https://github.com/tangentlabs/django-oscar-testsupport
+.. _django-oscar-easyrec: https://github.com/tangentlabs/django-oscar-easyrec
+.. _EasyRec: http://easyrec.org/
-The following extensions are in development:
+The following extensions are in development by Tangent:
+* django-oscar-stripe_ - Integration with the Stripe_ payment gateway
* django-oscar-gocardless_ - Integration with the GoCardless_ payment gateway
* django-oscar-jirafe_ - Integration with the Jirafe_ analytics package
* django-oscar-parachute_ - Import scripts for migrating away from non-Oscar
platforms.
+* django-oscar-eway_ - Integration with the eWay_ payment gateway.
* django-oscar-approval_ - Approval workflow for authorising new
orders/products.
+.. _django-oscar-stripe: https://github.com/tangentlabs/django-oscar-stripe
.. _django-oscar-stores: https://github.com/tangentlabs/django-oscar-stores
.. _django-oscar-parachute: https://github.com/tangentlabs/django-oscar-parachute
.. _django-oscar-approval: https://github.com/tangentlabs/django-oscar-approval
+.. _Stripe: https://stripe.com
+.. _django-oscar-eway: https://github.com/tangentlabs/django-oscar-eway
+.. _eWay: https://www.eway.com.au
+
+The following are community-written extensions:
+
+* django-oscar-unicredit_ - Integration with the Unicredit payment gateway
+* django-oscar-payments_ - Pluggable payments for Oscar
+* django-oscar-recurly_ - Integration with the Recurly payment gateway
+* oscar-sagepay_ - Payment integration with Sage Pay
+* django-oscar-erp_
Let us know if you're writing a new one!
+.. _django-oscar-unicredit: https://bitbucket.org/marsim/django-oscar-unicredit/
+.. _django-oscar-erp: https://bitbucket.org/zikzakmedia/django-oscar_erp
+.. _django-oscar-payments: https://github.com/Lacrymology/django-oscar-payments
+.. _django-oscar-recurly: https://github.com/mynameisgabe/django-oscar-recurly
+.. _oscar-sagepay: https://github.com/udox/oscar-sagepay
+
License
-------
@@ -151,10 +207,10 @@ Oscar is released under the permissive `New BSD license`_.
Case studies
------------
-Oscar is still in active development, but is used in production by a range of
+Oscar is still in active development but is used in production by a range of
companies, from large multinationals to small, boutique stores:
-Tangent projects:
+Selected Tangent projects:
* Tata Group - http://www.landmarkonthenet.com
* Carlsberg - Their global "We Deliver More" platform is powered by Oscar (but
@@ -162,6 +218,8 @@ Tangent projects:
* Chocolate Box - https://www.thechocolatebox.com.au
* The UK Labour party - http://shop.labour.org.uk
* Meridian Audio - http://www.meridian-audio.co.uk
+* Which Rightchoice - http://www.whichrightchoice.com
+* Freetix - http://www.freetix.com.au/
.. image:: https://github.com/tangentlabs/django-oscar/raw/master/docs/images/screenshots/landmark.thumb.png
:target: http://www.landmarkonthenet.com
@@ -178,12 +236,22 @@ Tangent projects:
.. image:: https://github.com/tangentlabs/django-oscar/raw/master/docs/images/screenshots/meridian.thumb.png
:target: http://www.meridian-audio.co.uk
+.. image:: https://github.com/tangentlabs/django-oscar/raw/master/docs/images/screenshots/rightchoice.thumb.png
+ :target: http://www.whichrightchoice.com
+
+.. image:: https://github.com/tangentlabs/django-oscar/raw/master/docs/images/screenshots/freetix.thumb.png
+ :target: http://www.freetix.com.au/
+
Non-Tangent:
* Dolbeau - http://www.dolbeau.ca/
* Sobusa - http://www.sobusa.fr/
* Laivee - http://laivee.pl
* Colinss - http://colinss.com
+* Audio App - https://audioapp.pl/
+* Anything Gift - http://www.anythinggift.co.uk
+* FP Sport - http://www.fpsport.it
+* Garmsby - https://garmsby.co.uk
.. image:: https://github.com/tangentlabs/django-oscar/raw/master/docs/images/screenshots/dolbeau.thumb.png
:target: http://www.dolbeau.ca
@@ -197,12 +265,50 @@ Non-Tangent:
.. image:: https://github.com/tangentlabs/django-oscar/raw/master/docs/images/screenshots/colinss.thumb.png
:target: http://www.colinss.com
+.. image:: https://github.com/tangentlabs/django-oscar/raw/master/docs/images/screenshots/audioapp.thumb.png
+ :target: https://audioapp.pl
+
+.. image:: https://github.com/tangentlabs/django-oscar/raw/master/docs/images/screenshots/anythinggift.thumb.png
+ :target: http://www.anythinggift.co.uk
+
+.. image:: https://github.com/tangentlabs/django-oscar/raw/master/docs/images/screenshots/fpsport.thumb.png
+ :target: https://www.fpsport.it
+
+.. image:: https://github.com/tangentlabs/django-oscar/raw/master/docs/images/screenshots/garmsby.thumb.png
+ :target: https://garmsby.co.uk
+
Many more on the way. If you use Oscar in production, please let us know.
-Would you like to work on Oscar?
---------------------------------
+.. image:: https://github.com/tangentlabs/django-oscar/raw/master/docs/images/logos/tangentlabs.jpg
+ :target: http://www.tangentlabs.co.uk/
+
+Oscar resources
+---------------
+
+Presentations:
-Tangent Labs are currently looking for python hackers to work on Oscar as well
+.. image:: https://github.com/tangentlabs/django-oscar/raw/master/docs/images/presentations/oscon2012.png
+ :target: https://speakerdeck.com/codeinthehole/writing-a-django-e-commerce-framework-1
+
+Looking for commercial support?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+If you are interested in having an Oscar project built for you, or for
+development of an existing Oscar site, Tangent can
+help. Please get in touch via `oscar@tangentlabs.co.uk`_ or via the `Tangent
+Snowball`_ site.
+
+.. _`oscar@tangentlabs.co.uk`: mailto:oscar@tangentlabs.co.uk
+.. _`Tangent Snowball`: http://www.tangentsnowball.com/products/oscar
+
+Want to get paid to work on Oscar?
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+`Tangent Labs`_ are currently looking for python hackers to work on Oscar as well
as some of other internal products and e-commerce projects. If this sounds
-interesting, please get in touch with @codeinthehole through Github or Twitter.
-The position is in Tangent's London offices.
+interesting, please email `recruitment@tangentlabs.co.uk`_.
+
+The position is in Tangent's London offices and you must have the appropriate
+visas to work in the UK.
+
+.. _`recruitment@tangentlabs.co.uk`: mailto:recruitment@tangentlabs.co.uk
diff --git a/create_migration.py b/create_migration.py
deleted file mode 100755
index bae629cbe20..00000000000
--- a/create_migration.py
+++ /dev/null
@@ -1,29 +0,0 @@
-#!/usr/bin/env python
-"""
-Convenience script to create migrations
-"""
-from optparse import OptionParser
-
-from tests.config import configure
-configure()
-
-
-def create_migration(app_label, **kwargs):
- from south.management.commands.schemamigration import Command
- com = Command()
- com.handle(app=app_label, **kwargs)
-
-
-if __name__ == '__main__':
- parser = OptionParser()
- parser.add_option('-i', '--initial', dest='initial',
- action='store_true', default=False)
- parser.add_option('-a', '--auto', dest='auto',
- action='store_true', default=False)
- parser.add_option('-e', '--empty', dest='empty',
- action='store_true', default=False)
- parser.add_option('-n', '--name', dest='name', default='')
- (options, args) = parser.parse_args()
- create_migration(args[0], initial=options.initial,
- auto=options.auto, empty=options.empty,
- name=options.name)
diff --git a/docs/Makefile b/docs/Makefile
index df38f4040a5..e26baeeda2b 100644
--- a/docs/Makefile
+++ b/docs/Makefile
@@ -37,38 +37,38 @@ clean:
-rm -rf $(BUILDDIR)/*
html:
- $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
+ $(SPHINXBUILD) -a -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
dirhtml:
- $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
+ $(SPHINXBUILD) -a -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
singlehtml:
- $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
+ $(SPHINXBUILD) -a -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
@echo
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
pickle:
- $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
+ $(SPHINXBUILD) -a -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
@echo
@echo "Build finished; now you can process the pickle files."
json:
- $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
+ $(SPHINXBUILD) -a -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
@echo
@echo "Build finished; now you can process the JSON files."
htmlhelp:
- $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
+ $(SPHINXBUILD) -a -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
@echo
@echo "Build finished; now you can run HTML Help Workshop with the" \
".hhp project file in $(BUILDDIR)/htmlhelp."
qthelp:
- $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
+ $(SPHINXBUILD) -a -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
@echo
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
@@ -77,7 +77,7 @@ qthelp:
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/django-oscar.qhc"
devhelp:
- $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
+ $(SPHINXBUILD) -a -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
@echo
@echo "Build finished."
@echo "To view the help file:"
@@ -86,45 +86,45 @@ devhelp:
@echo "# devhelp"
epub:
- $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
+ $(SPHINXBUILD) -a -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
@echo
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
latex:
- $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+ $(SPHINXBUILD) -a -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
@echo "Run \`make' in that directory to run these through (pdf)latex" \
"(use \`make latexpdf' here to do that automatically)."
latexpdf:
- $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
+ $(SPHINXBUILD) -a -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through pdflatex..."
make -C $(BUILDDIR)/latex all-pdf
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
text:
- $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
+ $(SPHINXBUILD) -a -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
@echo
@echo "Build finished. The text files are in $(BUILDDIR)/text."
man:
- $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
+ $(SPHINXBUILD) -a -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
@echo
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
changes:
- $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
+ $(SPHINXBUILD) -a -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
@echo
@echo "The overview file is in $(BUILDDIR)/changes."
linkcheck:
- $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
+ $(SPHINXBUILD) -a -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
@echo
@echo "Link check complete; look for any errors in the above output " \
"or in $(BUILDDIR)/linkcheck/output.txt."
doctest:
- $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
+ $(SPHINXBUILD) -a -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
@echo "Testing of doctests in the sources finished, look at the " \
"results in $(BUILDDIR)/doctest/output.txt."
diff --git a/docs/images/logos/labs-ts-oscar.jpg b/docs/images/logos/labs-ts-oscar.jpg
new file mode 100644
index 00000000000..7fa0316b7b3
Binary files /dev/null and b/docs/images/logos/labs-ts-oscar.jpg differ
diff --git a/docs/images/logos/oscar.png b/docs/images/logos/oscar.png
new file mode 100644
index 00000000000..bc1c2c67b1c
Binary files /dev/null and b/docs/images/logos/oscar.png differ
diff --git a/docs/images/logos/tangentlabs.jpg b/docs/images/logos/tangentlabs.jpg
new file mode 100644
index 00000000000..0996607c84b
Binary files /dev/null and b/docs/images/logos/tangentlabs.jpg differ
diff --git a/docs/images/presentations/oscon2012.png b/docs/images/presentations/oscon2012.png
new file mode 100644
index 00000000000..241fb1a7fed
Binary files /dev/null and b/docs/images/presentations/oscon2012.png differ
diff --git a/docs/images/screenshots/anythinggift.png b/docs/images/screenshots/anythinggift.png
new file mode 100644
index 00000000000..c85a7643b9a
Binary files /dev/null and b/docs/images/screenshots/anythinggift.png differ
diff --git a/docs/images/screenshots/anythinggift.thumb.png b/docs/images/screenshots/anythinggift.thumb.png
new file mode 100644
index 00000000000..e80836db5ae
Binary files /dev/null and b/docs/images/screenshots/anythinggift.thumb.png differ
diff --git a/docs/images/screenshots/audioapp.png b/docs/images/screenshots/audioapp.png
new file mode 100644
index 00000000000..4b4ef4e16e4
Binary files /dev/null and b/docs/images/screenshots/audioapp.png differ
diff --git a/docs/images/screenshots/audioapp.thumb.png b/docs/images/screenshots/audioapp.thumb.png
new file mode 100644
index 00000000000..d73aad80c01
Binary files /dev/null and b/docs/images/screenshots/audioapp.thumb.png differ
diff --git a/docs/images/screenshots/basket.thumb.png b/docs/images/screenshots/basket.thumb.png
index 59b551a536a..dfe4bf888cd 100644
Binary files a/docs/images/screenshots/basket.thumb.png and b/docs/images/screenshots/basket.thumb.png differ
diff --git a/docs/images/screenshots/browse.thumb.png b/docs/images/screenshots/browse.thumb.png
index 83bad13a897..3f73ba5ad13 100644
Binary files a/docs/images/screenshots/browse.thumb.png and b/docs/images/screenshots/browse.thumb.png differ
diff --git a/docs/images/screenshots/carlsberg.cch.thumb.png b/docs/images/screenshots/carlsberg.cch.thumb.png
index 7a7d58f1a4b..8dcc00fac1c 100644
Binary files a/docs/images/screenshots/carlsberg.cch.thumb.png and b/docs/images/screenshots/carlsberg.cch.thumb.png differ
diff --git a/docs/images/screenshots/chocolatebox.thumb.png b/docs/images/screenshots/chocolatebox.thumb.png
index a0c08c27fa1..bed75579dde 100644
Binary files a/docs/images/screenshots/chocolatebox.thumb.png and b/docs/images/screenshots/chocolatebox.thumb.png differ
diff --git a/docs/images/screenshots/colinss.thumb.png b/docs/images/screenshots/colinss.thumb.png
index 033e1c4db3c..a7520ffc0fa 100644
Binary files a/docs/images/screenshots/colinss.thumb.png and b/docs/images/screenshots/colinss.thumb.png differ
diff --git a/docs/images/screenshots/dashboard.thumb.png b/docs/images/screenshots/dashboard.thumb.png
index f70f93099e6..10cc82eed6a 100644
Binary files a/docs/images/screenshots/dashboard.thumb.png and b/docs/images/screenshots/dashboard.thumb.png differ
diff --git a/docs/images/screenshots/demo.browse.png b/docs/images/screenshots/demo.browse.png
new file mode 100644
index 00000000000..e20da8a73d4
Binary files /dev/null and b/docs/images/screenshots/demo.browse.png differ
diff --git a/docs/images/screenshots/demo.browse.thumb.png b/docs/images/screenshots/demo.browse.thumb.png
new file mode 100644
index 00000000000..97e11757534
Binary files /dev/null and b/docs/images/screenshots/demo.browse.thumb.png differ
diff --git a/docs/images/screenshots/demo.home.png b/docs/images/screenshots/demo.home.png
new file mode 100644
index 00000000000..4d8764c1282
Binary files /dev/null and b/docs/images/screenshots/demo.home.png differ
diff --git a/docs/images/screenshots/demo.home.thumb.png b/docs/images/screenshots/demo.home.thumb.png
new file mode 100644
index 00000000000..a1ddac4edb5
Binary files /dev/null and b/docs/images/screenshots/demo.home.thumb.png differ
diff --git a/docs/images/screenshots/detail.thumb.png b/docs/images/screenshots/detail.thumb.png
index dec3da64f19..cfdc64beaab 100644
Binary files a/docs/images/screenshots/detail.thumb.png and b/docs/images/screenshots/detail.thumb.png differ
diff --git a/docs/images/screenshots/dolbeau.thumb.png b/docs/images/screenshots/dolbeau.thumb.png
index d5ebd45ba71..fdc51a53348 100644
Binary files a/docs/images/screenshots/dolbeau.thumb.png and b/docs/images/screenshots/dolbeau.thumb.png differ
diff --git a/docs/images/screenshots/fpsport.thumb.png b/docs/images/screenshots/fpsport.thumb.png
new file mode 100644
index 00000000000..fa8ee35f2c9
Binary files /dev/null and b/docs/images/screenshots/fpsport.thumb.png differ
diff --git a/docs/images/screenshots/freetix.png b/docs/images/screenshots/freetix.png
new file mode 100644
index 00000000000..b7ef6619d9c
Binary files /dev/null and b/docs/images/screenshots/freetix.png differ
diff --git a/docs/images/screenshots/freetix.thumb.png b/docs/images/screenshots/freetix.thumb.png
new file mode 100644
index 00000000000..86a5648ce86
Binary files /dev/null and b/docs/images/screenshots/freetix.thumb.png differ
diff --git a/docs/images/screenshots/garmsby.thumb.png b/docs/images/screenshots/garmsby.thumb.png
new file mode 100644
index 00000000000..8ad722ae9f1
Binary files /dev/null and b/docs/images/screenshots/garmsby.thumb.png differ
diff --git a/docs/images/screenshots/labourshop.thumb.png b/docs/images/screenshots/labourshop.thumb.png
index 981d36a7a94..8cfae7e2710 100644
Binary files a/docs/images/screenshots/labourshop.thumb.png and b/docs/images/screenshots/labourshop.thumb.png differ
diff --git a/docs/images/screenshots/laivee.thumb.png b/docs/images/screenshots/laivee.thumb.png
index e540d70fa43..81880712fcd 100644
Binary files a/docs/images/screenshots/laivee.thumb.png and b/docs/images/screenshots/laivee.thumb.png differ
diff --git a/docs/images/screenshots/landmark.thumb.png b/docs/images/screenshots/landmark.thumb.png
index 5aff856036e..520533035ab 100644
Binary files a/docs/images/screenshots/landmark.thumb.png and b/docs/images/screenshots/landmark.thumb.png differ
diff --git a/docs/images/screenshots/meridian.thumb.png b/docs/images/screenshots/meridian.thumb.png
index cc5cc18109a..2291e25548c 100644
Binary files a/docs/images/screenshots/meridian.thumb.png and b/docs/images/screenshots/meridian.thumb.png differ
diff --git a/docs/images/screenshots/oscarcommerce.thumb.png b/docs/images/screenshots/oscarcommerce.thumb.png
index 0c5b1cd9639..e9a6ad09fad 100644
Binary files a/docs/images/screenshots/oscarcommerce.thumb.png and b/docs/images/screenshots/oscarcommerce.thumb.png differ
diff --git a/docs/images/screenshots/readthedocs.thumb.png b/docs/images/screenshots/readthedocs.thumb.png
index e2a83f91677..7385db184f4 100644
Binary files a/docs/images/screenshots/readthedocs.thumb.png and b/docs/images/screenshots/readthedocs.thumb.png differ
diff --git a/docs/images/screenshots/rightchoice.png b/docs/images/screenshots/rightchoice.png
new file mode 100644
index 00000000000..38a25e5b894
Binary files /dev/null and b/docs/images/screenshots/rightchoice.png differ
diff --git a/docs/images/screenshots/rightchoice.thumb.png b/docs/images/screenshots/rightchoice.thumb.png
new file mode 100644
index 00000000000..50bddf5b49e
Binary files /dev/null and b/docs/images/screenshots/rightchoice.thumb.png differ
diff --git a/docs/images/screenshots/sobusa.thumb.png b/docs/images/screenshots/sobusa.thumb.png
index e7373f7e63a..c640ce1f1c2 100644
Binary files a/docs/images/screenshots/sobusa.thumb.png and b/docs/images/screenshots/sobusa.thumb.png differ
diff --git a/docs/source/_old/offers.rst b/docs/source/_old/offers.rst
deleted file mode 100644
index 1f0a9317bcb..00000000000
--- a/docs/source/_old/offers.rst
+++ /dev/null
@@ -1,75 +0,0 @@
-===================
-Offers and vouchers
-===================
-
-The ``oscar.offers`` app offers functionality for basket-level offers and vouchers. This covers
-features such as:
-
-* 3-for-2 offers on fiction books
-* Buy one book, get a DVD for half price
-* A Christmas voucher code that gives 25% off all products until December 25th
-* All students get £5 off their first order
-* Visitors coming from an affiliate site get 10% off their order
-* A voucher code that can be used once by each customer and gives 25% off
-
-In short, it is very flexible.
-
-Basket-level offers
--------------------
-A conditional offer has metadata such as a name, description and date range (for when it is active)
-but is defined by two things:
-
-* A *Condition*, which is some criteria that the user's basket has to have met. These are
- either count- (e.g., must contain one fiction book) or value-based (e.g., must contain £10 or more
- of DVDs).
-* A *Benefit*, which is the discount that is applied to the basket.
-
-When an offer is applied the basket, the products that are used to meet the condition, and the
-products discounted by the benefit are "consumed" so that they are not available for other offers.
-
-Offers come in 4 types:
-
-* *Site offers* - Offers that are available to all users of the site. Every time a basket is looked
- up for a user, we attempt to apply these offers to give a discount. An example is a "3 for 2" offer
- on all fiction books.
-
-* *Voucher offers* - Offers that are available if you have attached a specific voucher code to your basket.
- For example, a voucher could be created that links to a 25% off offer on all products.
-
-* *User offers* - Offers available only to certain users - these are looked up by passing the ``auth.User``
- object to a look-up service that returns any relevant offers. This could be used to give student
- users a discount or something like that.
-
-* *Session offers* - Offers available for the duration of the current session. These have to be inserted
- into the session by some mechanism, but exist to allow functionality such as giving discount to
- users that come from an affiliate site.
-
-In practice, all these offers are loaded and merged into a single set which is then applied to the basket.
-
-When creating an offer, you need to specify which type of offer it is.
-
-Vouchers
---------
-
-A voucher is essentially a code which links through to a set of basket-level
-offers (see above). Note that you can have any number of vouchers attached to
-a basket.
-
-
-Basket discounts
-----------------
-
-* *Multibuy* - This gives the cheapest product in the condition range for free.
- This is normally used to build 3-for-2 offers and similar.
-
-* *Percentage discount* - A percentage discount off the basket products that are
- in the benefit range.
-
-* *Absolute discount* - An absolute discount off the basket products in the
- benefit range.
-
-* *Fixed price* -
-
-*
-
-
diff --git a/docs/source/conf.py b/docs/source/conf.py
index 5d5584cd311..bb0916d2d4e 100644
--- a/docs/source/conf.py
+++ b/docs/source/conf.py
@@ -227,6 +227,9 @@
[u'David Winterbottom'], 1)
]
+# Autodoc settings
+autoclass_content = 'both'
+
# Better documenting of Django models
# See http://djangosnippets.org/snippets/2533/
diff --git a/docs/source/howto/how_do_i_translate_oscar.rst b/docs/source/howto/how_do_i_translate_oscar.rst
deleted file mode 100644
index a6148232b94..00000000000
--- a/docs/source/howto/how_do_i_translate_oscar.rst
+++ /dev/null
@@ -1,58 +0,0 @@
-=========================
-How do I translate Oscar?
-=========================
-
-Before doing any translation work, ensure you are famility with `Django's i18n
-guidelines`_.
-
-.. _`Django's i18n guidelines`: https://docs.djangoproject.com/en/dev/topics/i18n/
-
-Contributing translations to Oscar
-----------------------------------
-
-To submit a new set of translations for Oscar, do the following:
-
-1. Fork the repo and install Oscar's repo then navigate to the ``oscar``
- folder::
-
- git clone git@github.com:$USERNAME/django-oscar.git
- cd django-oscar/
- mkvirtualenv oscar
- make sandbox
-
-2. Generate the message files for a given language::
-
- django-admin.py makemessages --locale=$LANGUAGE_CODE
-
-3. Use the Rosetta_ functionality within the sandbox to add translations for the
- new messages files.::
-
- cd sites/sandbox
- ./manage.py runserver
- open http://localhost:8000/rosetta
-
-.. _Rosetta: https://github.com/mbi/django-rosetta
-
-4. Send a pull request!::
-
- git checkout -b new-translation
- git add oscar/locale
- git commit
- git push origin new-translation
-
-Your work will be much appreciated.
-
-Translating Oscar within your project
--------------------------------------
-
-If Oscar does not provide translations for your language, or if you want to
-provide your own, do the following.
-
-Within your project, create a locale folder and a symlink to Oscar so that ``./manage.py
-makemessages`` finds Oscar's translatable strings::
-
- mkdir locale i18n
- ln -s $PATH_TO_OSCAR i18n/oscar
- ./manage.py makemessages --symlinks --locale=de
-
-This will create the message files that you can now translate.
diff --git a/docs/source/howto/how_to_change_a_url.rst b/docs/source/howto/how_to_change_a_url.rst
index 8abe880a46e..682d777acf6 100644
--- a/docs/source/howto/how_to_change_a_url.rst
+++ b/docs/source/howto/how_to_change_a_url.rst
@@ -2,31 +2,24 @@
How to change an existing URL pattern
=====================================
-Oscar has many views and associated URLs. Often you want to customised these
+Oscar has many views and associated URLs. Often you want to customise these
URLs for your domain. For instance, you might want to use American spellings
rather than British (``catalog`` instead of ``catalogue``).
-URLs in Oscar
--------------
+This How-to describes how to do just that.
+It builds upon the steps described in :doc:`/topics/customisation`. Please
+read it first and ensure that you've:
-Oscar's views and URLs use a tree of 'app' instances, each of which subclass
-``oscar.core.application.Application`` and provide ``urls`` property. Oscar has
-a root app instance in ``oscar/app.py`` which can be imported into your
-``urls.py``::
+* Created a Python module with the the same label
+* Added it as Django app to ``INSTALLED_APPS``
+* Created a custom ``app.py``
- # urls.py
- from oscar.app import application
-
- urlpatterns = patterns('',
- ... # Your other URLs
- (r'', include(application.urls)),
- )
-
-Customising
------------
+Example
+-------
-In order to customise Oscar's URLs, you need to use a custom app instance in
-your root ``urls.py`` instead of Oscar's default instance. Hence, to use
+In order to customise Oscar's URLs, you need to use a custom app instance
+instead of Oscar's default instance. ``/catalogue`` is wired up in the root
+application, so we need to replace that. Hence, to use
``catalog`` instead of ``catalogue``, create a subclass of Oscar's main
``Application`` class and override the ``get_urls`` method::
@@ -57,3 +50,16 @@ Now modify your root ``urls.py`` to use your new application instance::
)
All URLs containing ``catalogue`` previously are now displayed as ``catalog``.
+
+If you wanted to change URLs of a sub-app (e.g. ``/catalogue/category/``),
+you only need to replace the ``catalogue`` app. There's no need to change
+your ``urls.py`` or touch the root ``application`` instance. ``application``
+instances dynamically load their sub-apps, so it just pick up your replacement::
+
+ # oscar/app.py
+ class Shop(Application):
+ name = None
+
+ catalogue_app = get_class('catalogue.app', 'application')
+ customer_app = get_class('customer.app', 'application')
+ ...
diff --git a/docs/source/howto/how_to_configure_shipping.rst b/docs/source/howto/how_to_configure_shipping.rst
index cf431fa2d1a..c87212d3f3f 100644
--- a/docs/source/howto/how_to_configure_shipping.rst
+++ b/docs/source/howto/how_to_configure_shipping.rst
@@ -2,61 +2,127 @@
How to configure shipping
=========================
-Checkout flow
--------------
+Configuring shipping is not trivial. It generally requires creating a
+'shipping' app within your project where you can define your own shipping
+methods as well as a 'repository' class which determines when methods are
+available.
-Oscar's checkout is set-up to follow the following steps:
+This recipe explains in more detail how Oscar models shipping as well as the
+steps involved in configuring shipping for your project.
-1. Manage basket
-2. Enter/choose shipping address
-3. Choose shipping method
-4. Choose payment method
-5. Preview
-6. Enter payment details and submit
+How Oscar handles shipping charges
+----------------------------------
-Determining the methods available to a user
--------------------------------------------
+Oscar uses a "repository" class to manage shipping charges. The class is used
+in two ways:
-At the shipping method stage, we use a repository object to look up the
-shipping methods available to the user. These methods typically depend on:
+* _It provides a list of shipping methods available to the user._ This is used to
+ generate the content for the shipping methods page of checkout, where the user
+ can choose a shipping method. The methods available generally depend on the
+ user, the basket and the shipping address.
+
+* _It allows a shipping method to be retrieved based on a identifying code._ When
+ a user selects a shipping method during checkout, it is persisted in the
+ session using a code. This code is used to retrieve the chosen shipping
+ method when it is required.
+
+The default shipping repository `can be seen here`_. It defaults to only
+providing one shipping method, which has no charge.
+
+.. note::
+
+ Oscar's checkout process includes a page for choosing your shipping method.
+ If there is only one method available for your basket then it will be chosen
+ automatically and the user immediately redirected to the next step.
+
+Custom shipping charges
+-----------------------
+
+In order to control shipping logic for your project, you need to define your own
+repository class (see :doc:`how_to_override_a_core_class`). It normally makes
+sense to subclass the core ``Repository`` class and override the
+``get_shipping_methods`` and ``find_by_code`` methods.
+
+Here's a very simple example where all shipping costs are a fixed price,
+irrespective of basket and shipping address::
+
+ # myproject/shipping/repository.py
+
+ from decimal import Decimal as D
+ from oscar.apps.shipping import repository, methods as core_methods
+
+ class Repository(repository.Repository):
+ methods = [core_methods.FixedPrice(D('9.99'))]
+
+ def get_shipping_methods(self, user, basket, shipping_addr=None, **kwargs):
+ return self.prime_methods(basket, self.methods)
+
+ def find_by_code(self, code, basket):
+ for method in self.methods:
+ if code == method.code:
+ return self.prime_method(basket, method)
+
+Note that both these methods must return 'primed' method instances, which means
+the basket instance has been injected into the method. This allows the method
+instance to return the shipping charge directly without requiring the basket to
+be passed again (which is useful in templates).
+
+As you can see the ``get_shipping_methods`` can depend on several things:
* the user in question (e.g., staff get cheaper shipping rates)
* the basket (e.g., shipping is charged based on the weight of the basket)
* the shipping address (e.g., overseas shipping is more expensive)
-The default repository is ``oscar.apps.shipping.repository.Repository``, which
-has a method ``get_shipping_methods`` for returning all available methods. By
-default, the returned method will be ``oscar.apps.shipping.methods.Free``.
+Here's a more involved example repository that has two fixed price charges::
-Set a custom shipping methods
------------------------------
+ # myproject/shipping/repository.py
-To apply your domain logic for shipping, you will need to override
-the default repository class (see :doc:`how_to_override_a_core_class`) and alter
-the implementation of the ``get_shipping_methods`` method. This method
-should return a list of "shipping method" classes already instantiated
-and holding a reference to the basket instance.
+ from decimal import Decimal as D
+ from oscar.apps.shipping import repository, methods as core_methods
-Building a custom shipping method
----------------------------------
+ # We create subclasses so we can give them different codes and names
+ class Standard(core_methods.FixedPrice):
+ code = 'standard'
+ name = _("Standard shipping")
+
+ class Express(core_methods.FixedPrice):
+ code = 'express'
+ name = _("Express shipping")
+
+ class Repository(repository.Repository):
+ methods = [Standard(D('10.00')), Express(D('20.00'))]
+
+ def get_shipping_methods(self, user, basket, shipping_addr=None, **kwargs):
+ return self.prime_methods(basket, self.methods)
+
+ def find_by_code(self, code, basket):
+ for method in self.methods:
+ if code == method.code:
+ return self.prime_method(basket, method)
-A shipping method class must define two methods::
+.. _`can be seen here`: https://github.com/tangentlabs/django-oscar/blob/master/oscar/apps/shipping/repository.py
- method.basket_charge_incl_tax()
- method.basket_charge_excl_tax()
+Shipping methods
+----------------
-whose responsibilities should be clear. You can subclass ``oscar.apps.shipping.base.ShippingMethod``
-to provide the basic functionality.
+The repository class is responsible for return shipping method instances. Oscar
+defines several of these but it is easy to write your own, their interface is
+simple.
-Built-in shipping methods
--------------------------
+The base shipping method class ``oscar.apps.shipping.base.ShippingMethod`` (that
+all shipping methods should subclass has API:
-Oscar comes with several built-in shipping methods which are easy to use
-with a custom repository.
+.. autoclass:: oscar.apps.shipping.base.ShippingMethod
+ :members:
+
+Core shipping methods
+~~~~~~~~~~~~~~~~~~~~~
+
+The shipping methods that ship with Oscar are:
* ``oscar.apps.shipping.methods.Free``. No shipping charges.
-* ``oscar.apps.shipping.methods.WeightBased``. This is a model-driven method
+* ``oscar.apps.shipping.models.WeightBased``. This is a model-driven method
that uses two models: ``WeightBased`` and ``WeightBand`` to provide charges
for different weight bands. By default, the method will calculate the weight
of a product by looking for a 'weight' attribute although this can be
@@ -65,5 +131,24 @@ with a custom repository.
* ``oscar.apps.shipping.methods.FixedPrice``. This simply charges a fixed price for
shipping, irrespective of the basket contents.
-* ``oscar.apps.shipping.methods.OrderAndItemCharges``. This is a model which
+* ``oscar.apps.shipping.models.OrderAndItemCharges``. This is a model which
specifies a per-order and a per-item level charge.
+
+To apply your domain logic for shipping, you will need to override
+the default repository class (see :doc:`how_to_override_a_core_class`) and alter
+the implementation of the ``get_shipping_methods`` method. This method
+should return a list of "shipping method" classes already instantiated
+and holding a reference to the basket instance.
+
+Building a custom shipping method
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+At a minimum, a custom shipping method class should define a ``code`` and
+``name`` attribute to distinguish it from other methods. It is also normal to
+override the ``basket_charge_incl_tax`` and ``basket_charge_excl_tax`` methods
+to implement your custom shipping charge logic.
+
+.. tip::
+
+ Most of the shipping logic should live in the repository class, the method
+ instance is only responsble for returning the charge for a given basket.
diff --git a/docs/source/howto/how_to_configure_stock_messaging.rst b/docs/source/howto/how_to_configure_stock_messaging.rst
index e9e7bcd738f..c4614bf1d72 100644
--- a/docs/source/howto/how_to_configure_stock_messaging.rst
+++ b/docs/source/howto/how_to_configure_stock_messaging.rst
@@ -2,42 +2,10 @@
How to configure stock messaging
================================
-Stock messaging is controlled on a per-partner basis. A product's stockrecord
-has the following methods for messaging:
+Stock messaging is controlled by an
+:ref:`availability policy `
+which is loaded by the :ref:`strategy class `.
-.. autoclass:: oscar.apps.partner.abstract_models.AbstractStockRecord
- :members: availability, availability_code
-
-Both these methods delegate to a "partner wrapper" instance. These are defined
-in the ``OSCAR_PARTNER_WRAPPERS`` setting which is a dict mapping from partner
-code to a class path, for instance::
-
- # settings.py
- OSCAR_PARTNER_WRAPPERS = {
- 'partner-a': 'myproject.wrappers.PartnerAWrapper',
- }
-
-The default wrapper is :class:`oscar.apps.partner.wrappers.DefaultWrapper`,
-which provides methods of the same name.
-
-.. autoclass:: oscar.apps.partner.wrappers.DefaultWrapper
- :members: availability, availability_code
-
-Custom wrappers should subclass this class and override the appropriate methods.
-Here's an example wrapper that provides custom availability messaging::
-
- # myproject/wrappers.py
- from oscar.apps.partner import wrappers
-
-
- class PartnerAWrapper(wrappers.DefaultWrapper):
-
- def availability(self, stockrecord):
- if stockrecord.net_stock_level > 0:
- return "Available to buy now!"
- return "Sorry, not available"
-
- def availability_code(self, stockrecord):
- if stockrecord.net_stock_level > 0:
- return "icon_tick"
- return "icon_cross"
+To set custom availability messaging, use your own strategy class to return the
+appropriate availability policy. It's possible to return different availability
+policies depending on the user, request and product in question.
diff --git a/docs/source/howto/how_to_configure_the_dashboard_navigation.rst b/docs/source/howto/how_to_configure_the_dashboard_navigation.rst
index 816162b230a..13d46864be5 100644
--- a/docs/source/howto/how_to_configure_the_dashboard_navigation.rst
+++ b/docs/source/howto/how_to_configure_the_dashboard_navigation.rst
@@ -45,7 +45,7 @@ Although you have your menu in the dashboard now, it doesn't look as
nice as the other menu items that have icons displayed next to them. So
you probably want to add an icon to your heading.
-Oscar uses `Font Awesome`_ for its icons which makes it very simple to
+Oscar uses `Font Awesome`_ for its icons which makes it very simple to add
an icon to your dashboard menu. All you need to do is find the right icon
for your menu item. Check out `the icon list`_ to find one.
diff --git a/docs/source/howto/how_to_create_a_custom_benefit.rst b/docs/source/howto/how_to_create_a_custom_benefit.rst
index a4c3fbf5193..e69bf32b109 100644
--- a/docs/source/howto/how_to_create_a_custom_benefit.rst
+++ b/docs/source/howto/how_to_create_a_custom_benefit.rst
@@ -23,7 +23,7 @@ Custom benefits
A custom benefit can be used by creating a benefit class and registering it so
it is available to be used.
-A benefit class must by a proxy class and have the following methods::
+A benefit class must be a proxy class and have the following methods::
from oscar.apps.offer import models
@@ -41,7 +41,7 @@ A benefit class must by a proxy class and have the following methods::
This is used in the dashboard when selecting benefits for offers.
"""
- def apply(self, basket, condition, offer=None):
+ def apply(self, basket, condition, offer):
"""
Apply the benefit to the passed basket and mark the appropriate
items as consumed.
@@ -88,7 +88,7 @@ Here's an example of a post-order action benefit::
description = "Changes customer's name"
- def apply(self, basket, condition, offer=None):
+ def apply(self, basket, condition, offer):
# We need to mark all items from the matched condition as 'consumed'
# so that they are unavailable to be used with other offers.
condition.consume_items(basket, ())
@@ -101,4 +101,3 @@ Here's an example of a post-order action benefit::
basket.owner.save()
return "Your name has been changed to Barry!"
return "We were unable to change your name as you are not signed in"
-
diff --git a/docs/source/howto/how_to_create_a_custom_condition.rst b/docs/source/howto/how_to_create_a_custom_condition.rst
index 4210e201e50..c8f814f7ad2 100644
--- a/docs/source/howto/how_to_create_a_custom_condition.rst
+++ b/docs/source/howto/how_to_create_a_custom_condition.rst
@@ -16,8 +16,8 @@ Condition class.
At a minimum, a custom condition must:
* have a ``name`` attribute
-* have an ``is_satisified`` method that takes a basket instance and returns a
- boolean
+* have an ``is_satisfied`` method that takes a basket instance and an offer
+ instance and returns a boolean
It can also implement:
@@ -32,7 +32,7 @@ It can also implement:
* a ``is_partially_satisfied`` method that tests to see if the customer's basket
partially satisfies the condition (ie when you might want to show them an
- upsel message)
+ upsell message)
Silly example::
@@ -44,7 +44,7 @@ Silly example::
class Meta:
proxy = True
- def is_satisfied(self, basket):
+ def is_satisfied(self, offer, basket):
if not basket.owner:
return False
return basket.owner.first_name.lower() == 'barry'
@@ -56,9 +56,9 @@ To make this condition available to be used in offers, do the following::
from oscar.apps.offer.custom import create_condition
- create_range(BasketOwnerCalledBarry)
+ create_condition(BasketOwnerCalledBarry)
-Now you should see this range in the dashboard when creating/updating an offer.
+Now you should see this condition in the dashboard when creating/updating an offer.
Deploying custom conditions
---------------------------
@@ -66,4 +66,4 @@ Deploying custom conditions
To avoid manual steps in each of your test/stage/production environments, use
South's `data migrations`_ to create conditions.
-.. _`data migrations`: http://south.readthedocs.org/en/latest/tutorial/part3.html#data-migrations
\ No newline at end of file
+.. _`data migrations`: http://south.readthedocs.org/en/latest/tutorial/part3.html#data-migrations
diff --git a/docs/source/howto/how_to_customise_a_view.rst b/docs/source/howto/how_to_customise_a_view.rst
new file mode 100644
index 00000000000..883853d70d3
--- /dev/null
+++ b/docs/source/howto/how_to_customise_a_view.rst
@@ -0,0 +1,49 @@
+=======================
+How to customise a view
+=======================
+
+Oscar has many views. This How-to describes how to customise one of them for
+your project. It builds upon the steps described in
+:doc:`/topics/customisation`. Please read it first and ensure that you've:
+
+* Created a Python module with the the same label
+* Added it as Django app to ``INSTALLED_APPS``
+* Use custom ``app.py``
+
+Example
+-------
+
+Create a new homepage view class in ``myproject.promotions.views`` - you can subclass
+Oscar's view if you like::
+
+ from oscar.apps.promotions.views import HomeView as CoreHomeView
+
+ class HomeView(CoreHomeView):
+ template_name = 'promotions/new-homeview.html'
+
+In this example, we set a new template location but it's possible to customise the view
+in any imaginable way.
+
+If you want to change the template, create the alternative template
+``new-homeview.html``. This could either be
+in a project-level ``templates`` folder that is added to your ``TEMPLATE_DIRS``
+settings, or a app-level ``templates`` folder within your 'promotions' app. For
+now, put something simple in there, such as::
+
+
+
+ You have successfully overridden the homepage template.
+
+
+
+Now you can hook it up in your local ``app.py``::
+
+ # myproject/promotions/app.py
+ from oscar.apps.promotions.app import PromotionsApplication as CorePromotionsApplication
+
+ from myproject.promotions.views import HomeView
+
+ class PromotionsApplication(CorePromotionsApplication):
+ home_view = HomeView
+
+ application = PromotionsApplication()
diff --git a/docs/source/howto/how_to_customise_an_app.rst b/docs/source/howto/how_to_customise_an_app.rst
deleted file mode 100644
index 3e011f4bbbf..00000000000
--- a/docs/source/howto/how_to_customise_an_app.rst
+++ /dev/null
@@ -1,156 +0,0 @@
-=======================
-How to customise an app
-=======================
-
-A core part of how Oscar can be customised is to create a local version of one
-of Oscar's apps so that it can be modified and extended. Creating a local
-version of an app allows customisation of any of the classes within the
-corresponding app in oscar.
-
-The way this is done involves a few steps, which are detailed here.
-
-Method
-======
-
-1. Create an app within your project with the same "app label" as an app in oscar. Eg,
- to create a local version of ``oscar.apps.order``, create something like ``myproject.order``.
-
-2. Ensure the ``models.py`` in your local app imports all the models from Oscar's version::
-
- # models.py
- from oscar.apps.order.models import *
-
-3. Replace Oscar's version of the app with your new version in ``INSTALLED_APPS``.
-
-
-Worked example
-==============
-
-Suppose you want to modify the homepage view class, which by default is defined in
-``oscar.apps.promotions.views.HomeView``. This view is bound to a URL within the
-``PromotionsApplication`` class in ``oscar.apps.promotions.app`` - hence we need to
-override this application class to be able to use a different view.
-
-By default, your base ``urls.py`` should include Oscar's URLs as so::
-
- # urls.py
- from oscar.app import application
-
- urlpatterns = patterns('',
- ...
- (r'', include(application.urls)),
- )
-
-To get control over the mapping between URLs and views, you need to use a local
-``application`` instance, that (optionally) subclasses Oscar's. Hence, create
-``myproject/app.py`` with contents::
-
- # myproject/app.py
- from oscar.app import Shop
-
- class BaseApplication(Shop):
- pass
-
- application = BaseApplication()
-
-No customisation for now, that will come later, but you now have control over which
-URLs and view functions are used.
-
-Now hook this up in your ``urls.py``::
-
- # urls.py
- from myproject.app import application
-
- urlpatterns = patterns('',
- ...
- (r'', include(application.urls)),
- )
-
-The next step is to create a local app with the same name as the app you want to override::
-
- mkdir myproject/promotions
- touch myproject/promotions/__init__.py
- touch myproject/promotions/models.py
-
-The ``models.py`` file should import all models from the oscar app being overridden::
-
- # myproject/promotions/models.py
- from oscar.apps.promotions.models import *
-
-Now replace ``oscar.apps.promotions`` with ``myproject.promotions`` in the
-``INSTALLED_APPS`` setting in your settings file. To do it, you will need to let
-Oscar know that you're replacing the corresponding core app with yours. You can
-do that by supplying an extra argument to ``get_core_apps`` function::
-
- # myproject/settings.py
-
- from oscar import get_core_apps
- # ...
- INSTALLED_APPS = [
- ] + get_core_apps(['myproject.promotions'])
-
-The ``get_core_apps`` function will replace ``oscar.apps.promotions`` with
-``myproject.promotions``.
-
-Now create a new homepage view class in ``myproject.promotions.views`` - you can subclass
-Oscar's view if you like::
-
- from oscar.apps.promotions.views import HomeView as CoreHomeView
-
- class HomeView(CoreHomeView):
- template_name = 'promotions/new-homeview.html'
-
-In this example, we set a new template location but it's possible to customise the view
-in any imaginable way.
-
-Now create the alternative template ``new-homeview.html``. This could either be
-in a project-level ``templates`` folder that is added to your ``TEMPLATE_DIRS``
-settings, or a app-level ``templates`` folder within your 'promotions' app. For
-now, put something simple in there, such as::
-
-
-
- You have successfully overridden the homepage template.
-
-
-
-Next, create a new ``app.py`` for your local promotions app which maps your new ``HomeView``
-class to the homepage URL::
-
- # myproject/promotions/app.py
- from oscar.apps.promotions.app import PromotionsApplication as CorePromotionsApplication
-
- from myproject.promotions.views import HomeView
-
- class PromotionsApplication(CorePromotionsApplication):
- home_view = HomeView
-
- application = PromotionsApplication()
-
-Finally, hook up the new view to the homepage URL::
-
- # myproject/app.py
- from oscar.app import Shop
-
- from myproject.promotions.app import application as promotions_app
-
- class BaseApplication(Shop):
- promotions_app = promotions_app
-
- application = BaseApplication()
-
-Quite long-winded, but once this step is done, you have lots of freedom to customise
-the app in question.
-
-Django admin
-------------
-
-One pain point with replacing one of Oscar's apps with a local one in
-``INSTALLED_APPS`` is that admin integration is lost from the original
-app. If you'd like to use the Django admin functionality you just need
-to run the register code in the replaced app's ``admin.py``::
-
- # myprojects/promotions/admin.py
- import oscar.apps.promotions.admin
-
-This isn't great but we haven't found a better way as of yet.
diff --git a/docs/source/howto/how_to_customise_models.rst b/docs/source/howto/how_to_customise_models.rst
index 8b354b207fd..cf608ec414d 100644
--- a/docs/source/howto/how_to_customise_models.rst
+++ b/docs/source/howto/how_to_customise_models.rst
@@ -2,16 +2,19 @@
How to customise models
=======================
-You must first create a local version of the app that you wish to customise. This
-involves creating a local app with the same name and importing the equivalent models
-from Oscar into it.
+This How-to describes how to replace Oscar models with your own. This allows you
+to add fields and custom methods. It builds upon the steps described in
+:doc:`/topics/customisation`. Please read it first and ensure that you've:
+
+* Created a Python module with the the same app label
+* Added it as Django app to ``INSTALLED_APPS``
Example
-------
-Suppose you want to add a video_url field to the core product model. This means that
-you want your application to use a subclass of ``oscar.apps.catalogue.models.Product`` which
-has an additional field.
+Suppose you want to add a ``video_url`` field to the core product model. This means
+that you want your application to use a subclass of
+:class:`oscar.apps.catalogue.abstract_models.AbstractProduct` which has an additional field.
The first step is to create a local version of the "catalogue" app. At a minimum, this
involves creating ``catalogue/models.py`` within your project and changing ``INSTALLED_APPS``
@@ -32,33 +35,36 @@ Next, you can modify the ``Product`` model through subclassing::
Make sure to import the remaining Oscar models at the bottom of your file.
-The last thing you need to do now is make Django update the database schema and
-create a new column in the product table. We recommend to use South migrations
-for this (internally Oscar already uses it) so all you need to do is create a
-new schema migration. Depending on your setup you should follow one of these
-two options:
-
-1. You **have not** run ``./manage.py migrate`` before
+.. tip::
- You can simply generate a new initial migration using::
+ Using ``from ... import *`` is strange isn't it? Yes it is, but it needs to
+ be done at the bottom of the module due to the way Django registers models.
+ The order that model classes are imported makes a difference, with only the
+ first one for a given class name being registered.
- ./manage.py schemamigration catalogue --initial
+The last thing you need to do now is make Django update the database schema and
+create a new column in the product table. We recommend using South migrations
+for this (internally Oscar already does this) so all you need to do is create a
+new schema migration.
-2. You **have** run ``./manage.py migrate`` before
+It is possible to simply create a new catalogue migration (using ``./manage.py
+schemamigration catalogue --auto``) but this isn't recommended as any
+dependencies between migrations will need to be applied manually (by adding a
+``depends_on`` attribute to the migration class).
- You have to copy the ``migrations`` directory from ``oscar/apps/catalogue``
- (the same as the ``models.py`` you just copied) and put it into your
- ``catalogue`` app.
- Now create a new (additional) schemamigration using the ``schemamigration``
- management command and follow the instructions::
+The recommended way to handle migrations is to copy the ``migrations`` directory
+from ``oscar/apps/catalogue`` into your new ``catalogue`` app. Then you can
+create a new (additional) schemamigration using the ``schemamigration``
+management command::
./manage.py schemamigration catalogue --auto
+which will pick up any customisations to the product model.
+
To apply the migration you just created, all you have to do is run
``./manage.py migrate catalogue`` and the new column is added to the product
table in the database.
-
Customising Products
--------------------
diff --git a/docs/source/howto/how_to_customise_oscar_communications.rst b/docs/source/howto/how_to_customise_oscar_communications.rst
new file mode 100644
index 00000000000..bea0c591d4a
--- /dev/null
+++ b/docs/source/howto/how_to_customise_oscar_communications.rst
@@ -0,0 +1,85 @@
+Customising Oscar's communications
+==================================
+
+Oscar provides the ability to customise the emails sent out to customers.
+
+There are two main ways this can be achieved, either in code (via template
+files) or in the database (via Dashboard > Content > Email templates).
+
+Communications API
+------------------
+
+First, it's important to understand a little about how the Communications API
+works.
+
+Oscar has a model called a ``CommunicationEventType``. When preparing an email
+to send out to a customer, the client code will do something like this::
+
+ commtype_code = 'SOME_EVENT'
+ context = {'customer': customer, 'something_else': 'Some more context.'}
+
+ try:
+ event_type = CommunicationEventType.objects.get(code=commtype_code)
+ except CommunicationEventType.DoesNotExist:
+ messages = CommunicationEventType.objects.get_and_render(commtype_code, ctx)
+ else:
+ messages = event_type.get_messages(ctx)
+
+What's happening here is:
+
+- The code defines an arbitrary communication type code to be treated as the
+ reference for this particular type of communication. For example, the
+ communication type code used when sending an order email confirmation is
+ ``'ORDER_PLACED'``.
+- The database is checked for a ``CommunicationEventType`` with this
+ communication type code. If it does, it renders the messages using that model
+ instance, passing in some context.
+- Otherwise, it uses the ``get_and_render()`` method to render the messages,
+ which uses templates instead.
+
+So, your first step when customising the emails sent out is to work out what
+communication type code is being used to send out the email. The easiest way to
+work this out is usually to look through the email templates in
+``templates/oscar/customer/emails``: if the email template is called, say,
+``commtype_order_placed_body.html``, then the code will be ``'ORDER_PLACED'``.
+See 'Customising through code' below.
+
+Customising through code
+------------------------
+
+Customising emails through code uses Django's standard template inheritance.
+
+The first step is to locate the template for the particular email, which is
+usually in templates/oscar/customer/emails. Then, in a template directory that
+takes precedence over the oscar templates directory, copy the file and customise
+it. For example, to override the
+``templates/oscar/customer/emails/commtype_order_placed_body.html`` template,
+create the file ``customer/emails/commtype_order_placed_body.html`` in your
+template directory.
+
+Note that usually emails have three template files associated with them: the
+email subject line (``commtype_CODE_subject.txt``), the html version
+(``commtype_CODE_body.html``) and the text version (commtype_CODE_body.txt).
+Usually you will want to make sure you override BOTH the html and the text
+version.
+
+Customising through code will not work if there is a template defined in the
+database instead (see below).
+
+
+Customising through the database
+--------------------------------
+
+Oscar provides a dashboard interface to allow admins to customise the emails.
+
+To enable this for a particular communication event type, log in to the admin
+site and create a new ``CommunicationEventType``. The code you use is the
+important thing: it needs to match the communication event code used when
+rendering the messages. For example, to override the order confirmation email,
+you need to create a ``CommunicationEventType`` with a code ``'ORDER_PLACED'``.
+
+Once you have created the ``CommunicationEventType``, you can edit it using the
+(much better) dashboard interface at Dashboard > Content > Email templates.
+
+If you have an email template defined in the database it will override any
+template files.
\ No newline at end of file
diff --git a/docs/source/howto/how_to_customise_templates.rst b/docs/source/howto/how_to_customise_templates.rst
index 1da423e4319..b5df0fa47f4 100644
--- a/docs/source/howto/how_to_customise_templates.rst
+++ b/docs/source/howto/how_to_customise_templates.rst
@@ -23,6 +23,7 @@ as so::
TEMPLATE_LOADERS = (
'django.template.loaders.filesystem.Loader',
'django.template.loaders.app_directories.Loader',
+ 'django.template.loaders.eggs.Loader',
)
import os
@@ -88,12 +89,12 @@ Apart from overriding ``catalogue/partials/product.html`` to change the looks
for all products, you can also override it for individual products by placing
templates in ``catalogue/partials/product/upc-%s.html`` or
``catalogue/partials/product/class-%s.html``, where ``%s`` is the product's UPC
-or product class in lower case, respectively.
+or class's slug, respectively.
Example: Changing the analytics package
---------------------------------------
-Support you want to use an alternative analytics package to Google analytics.
+Suppose you want to use an alternative analytics package to Google analytics.
We can achieve this by overriding templates where the analytics urchin is loaded
and called.
@@ -102,7 +103,7 @@ Analytics partial. We want to replace this with our own code. To do this,
create a new ``base.html`` in your project that subclasses the original::
# yourproject/templates/base.html
- {% extends oscar/base.html %}
+ {% extends 'oscar/base.html' %}
{% block tracking %}
+
{% endblock %}
diff --git a/oscar/templates/oscar/basket/basket.html b/oscar/templates/oscar/basket/basket.html
index 2b5427e73e9..44400803a47 100644
--- a/oscar/templates/oscar/basket/basket.html
+++ b/oscar/templates/oscar/basket/basket.html
@@ -1,17 +1,27 @@
{% extends "layout.html" %}
-{% load currency_filters %}
{% load thumbnail %}
{% load i18n %}
+{% load url from future %}
{% block title %}
-{% trans "Basket" %} | {{ block.super }}
+ {% trans "Basket" %} | {{ block.super }}
+{% endblock %}
+
+{% block breadcrumbs %}
+
{% endblock %}
{# Hide mini-basket so we don't have two baskets to keep in sync #}
{% block mini_basket %}{% endblock %}
{% block headertext %}
-{% trans "Basket" %}
+ {% trans "Basket" %}
{% endblock %}
{% block content %}
@@ -20,9 +30,10 @@
{% endblock content %}
{% block onbodyload %}
-{# We pass in the URL to send AJAX requests to #}
-var options = {
- 'basketURL': '{% url basket:summary %}'
-};
-oscar.basket.init(options);
+ {{ block.super }}
+ {# We pass in the URL to send AJAX requests to #}
+ var options = {
+ 'basketURL': '{% url 'basket:summary' %}'
+ };
+ oscar.basket.init(options);
{% endblock %}
diff --git a/oscar/templates/oscar/basket/messages/new_total.html b/oscar/templates/oscar/basket/messages/new_total.html
index 1fd10a57cab..32a6b809d37 100644
--- a/oscar/templates/oscar/basket/messages/new_total.html
+++ b/oscar/templates/oscar/basket/messages/new_total.html
@@ -1,3 +1,4 @@
+{% load url from future %}
{% load i18n %}
{% load currency_filters %}
@@ -5,15 +6,17 @@
{% if basket.is_empty %}
{% trans "Your basket is now empty" %}
{% else %}
- {% blocktrans with total=basket.total_incl_tax|currency %}
- Basket total now {{ total }}.
- {% endblocktrans %}
+ {% if basket.is_tax_known %}
+ {% trans "Basket total now" %} {{ basket.total_incl_tax|currency:basket.currency }}
+ {% else %}
+ {% trans "Basket total now" %} {{ basket.total_excl_tax|currency:basket.currency }}
+ {% endif %}
{% endif %}
-{% if show_buttons %}
+{% if include_buttons %}
- {% trans "View basket" %}
- {% trans "Checkout now" %}
+ {% trans "View basket" %}
+ {% trans "Checkout now" %}
{% endif %}
diff --git a/oscar/templates/oscar/basket/partials/basket_content.html b/oscar/templates/oscar/basket/partials/basket_content.html
index 43adc4169a5..2fb592d5443 100644
--- a/oscar/templates/oscar/basket/partials/basket_content.html
+++ b/oscar/templates/oscar/basket/partials/basket_content.html
@@ -1,172 +1,211 @@
+{% load url from future %}
{% load i18n %}
{% load thumbnail %}
{% load currency_filters %}
+{% load stockrecord_tags %}
{% if basket_warnings %}
{% trans "Important messages about items in your basket" %}
- {% for warning in basket_warnings %}
- {{ warning }}
- {% endfor %}
+ {% for warning in basket_warnings %}
+ {{ warning }}
+ {% endfor %}
{% endif %}
{% if upsell_messages %}
-
-
{% trans "You could be missing out on offers!" %}
- {% for upsell in upsell_messages %}
- {% blocktrans with message=upsell.message url=upsell.offer.get_absolute_url offer_name=upsell.offer.name %}
-
- {% endblocktrans %}
- {% endfor %}
-
+
+
{% trans "You could be missing out on offers!" %}
+ {% for upsell in upsell_messages %}
+ {% blocktrans with message=upsell.message url=upsell.offer.get_absolute_url offer_name=upsell.offer.name %}
+
+ {% endblocktrans %}
+ {% endfor %}
+
{% endif %}
{% if not basket.is_empty %}
{% block basket_form_headers %}
-
-
-
{% trans "Items to buy now" %}
-
{% trans "Quantity" %}
-
{% trans "Price" %}
+
+
+
{% trans "Items to buy now" %}
+ {% trans "Quantity" %}
+ {% trans "Price" %}
+ {% trans "Total" %}
+
-
{% endblock %}
{% block basket_form_main %}
-