Streamline Benefit and Condition name and description handling
This commit was triggered by a recursion problem mentioned here:
8199da2100 (commitcomment-7387486)
It now unifies handling for name and description across both conditions
and benefits:
* Declaring a name property is required for any proxy class. A few
classes had a description declared, but no name. But given that the
description is the more verbose version, and is allowed to include
HTML, it makes sense to still require a name. The declared
descriptions in the models that only had one property are better
suited for @name anyway.
* It drops the max_unaffected_items logic for Benefits. That was only
applied if calling via the non-proxy class, and feels more like it
should be a description anyway.
* __str__ always returns self.name. Anything more complex with that
means we might run into problems with the python_2_unicode_compatible
decorator.
I also added tests for the changes, and verified the tests fail without
my changes.
The previous implementation was too tightly coupled to the actual search
process, and rather verbose. It also had issues for translators in the
case of searching for both UPC and title.
This commit simplifies the description handling and provides a hook to
plug in more advanced descriptions. But I think a visual indication of
"those results are filtered" is a lot more useful than any description,
no matter how detailed.
Furthermore, this commit swaps out the "Create product" and "Search
products" sections to visually tie the search and search results closer
together.
Remove recently edited section on dashboard product list
The same thing can be achived by using the sorting function of the
regular product listings. In fact, I think sorting by recently edited
makes so much sense, that after an ad-hoc consultation in my coworking
office, I've decided to make it the new default.
My argument would be that one either searches for a specific product
that hasn't been touched in a while, or will want to amend a change one
recently did.
Fixes #1454.
Fixes #1460.
bdeb882 limited the dashboard's product list to parent and stand-alone
products, and did away with separate columns for parents and children.
After merging master, the dashboard product table was replaced by
a table generated by tables2. This commit redoes the part of bdeb882 to
replace the separate columns by a "variants" column that's more
informative.
While at it, I also added translatable names for the other columns.
This change:
- Alters the logical flow so the deletion of products takes place in the
`delete` method rather than `get_success_url`. As per SRP, I don't
think the `get_success_url` method should write to the DB.
- Fixes a logical error around child product deletions. We need to test
if the product being deleted is a last child *before* deleting it as
this changes the result.
Adjust URL for creating variant product in dashboard
Why?
- s/_/-/
- I try and follow a RESTy approach to URLs where the parent identifier
is to the left of any action or subordinates resources. (I'm sure
there are other examples in Oscar where we don't follow this).
This fixes two issues:
1) The code didn't take into account that self.format will be ignored by
Django if USE_L10N=True, unless a format was specified when constructing
the Widget. Remedied by moving the code to render because the current
language is determined at request time, not at object construction time,
and looking up the correct format there.
2) The code couldn't handle date formats that include dots, like
31.12.2014.
Fixes #1440.
We have differing logic on how to check the referrer for safety, which
should be bundled in one place. Plus it's annoying to have to remember
the typo in REFERER.
@aaugustin helpfully pointed us towards is_safe_url(), so that's the
best thing to use anyway.
Fixes #1221.
Update handling of child product for product ranges
This commit addresses issue #1253.
Currently, the offers app doesn't really consider child products;
behaviour is undefined. This commit addresses the fact: for now, we
assume that child and parent products are tightly coupled, and forbid
child products in a range. You can only add the parent product (and
with it all children).
This requirement might be lifted in the future, but that will mean
additional complexity and we will see if it's necessary.
Closes #1253.
create_range method doesn't ignore existing ranges again
The functionality to have it fetch an existing range instead of loudly
complaining when a range already exists has been added as part of #1053.
But @codeinthehole and I agree that a method called create_range
shouldn't silently ignore an existing range, and can't think of a use
case anymore.
* Removed unused _save method. It's not called anywhere.
* Simplified comment and logic for display_order
* Reordered imports
* Used items() instead of six.iteritems() because create_range does not
get complex kwargs
* Removed a duplicate test
* Test for the correct exception
Ensure offers consider parent categories for child products
A variant (child) product should not have categories. We need a new method
to get product categories, either for a product or for a parent product
if the parent is set.
This wrapper method is used when testing if product belongs to a range by
category.
Fixes #1218.
Explain why we can't move Abstract[Shipping|Billing]Address
Technically, they belong into the order app, and AbstractPartnerAddress
belongs into the partner app. I think they're in there because
AbstractUserAddress depends on AbstractShippingAddress. And maybe also
because trying to move them creates a rabbit hole of circular import
issues, which is why I gave up.
Similarily to benefits, conditions either need a custom proxy class or
have a type, range and value defined. This wasn't clear from the
documentation and the fact that the proxy() method happily returned
self.
This was raised in #1401.
We only needed it because Django 1.4 shipped with a pretty old version
of six. Support for that has been removed, and Django 1.5 ships with six
1.6.1, which is more current than we required.
This nicely avoids an issue with django-extra-views pinning a six
version which caused the sandbox build to fail:
https://travis-ci.org/tangentlabs/django-oscar/jobs/32223978#L971
Django's admin interface is not supported; the Oscar dashboard should be
used. It is still provided with the sandbox because it is convenient for
developers, but any code that goes beyond basic ModelAdmin syntax is a
maintenance burden.
Closes #1215.
Fix duplicate communication events created for orders
As reported in #1437, when a communication event type for code
ORDER_PLACED is in the database, both the OrderPlacementMixin and the
dispatcher create a CommunicationEvent. That's no good.
This fix diverges from the suggestion in #1437, because conceptually,
communication events are created for audit purposes and the creation
belongs more into the dispatcher than the view mixin.
Fixes #147.
Use plain textarea widget for email template editing
The dashboard communications app allows editing database-backed email
templates. The HTML body part had TinyMCE enabled, but I could not find
evidence that TinyMCE supports Django's template syntax. It definitely
caused an issue as reported in #1356.
Also use "fields" instead of "exclude" because that's good practice.
Closes #1356.
Update documentation to include all shipping methods, fix typo on configure shipping page
Add docstrings to the following classes in 'oscar.apps.shipping.methods':
* Free
* FixedPrice
* TaxExclusiveOfferDiscount
* TaxInclusiveOfferDiscount
Fix typo in 'docs/source/howto/how_to_configure_shipping.rst':
* Change 'shipping.addr' to 'shipping_addr'
It only prevents adding a product to a range; offers can be applied
nonetheless (despite the docs saying otherwise). The same functionality
can be achieved by overriding get_is_discountable, so it can be safely
removed.
Issue #855 is caused when deleting the middle of three product images in
the dashboard. A quick workaround is to renumber the image order values
when deleting an image. Eventually, this should be readressed as part of
issue #856.
This commit is the squashed version of #1429.
Overide delete() on AbstractProductImage.
Ensures the display order is always in consecutive order.
Cleans up after TestProductImages is run.
Fixes #855.
Closes #1429.
Django stores the class name of the auth backend used to authenticate a
user. The simple assignment before meant that the new name was stored in
the session data, but it might not be in the available auth backends.
Hence logging in would fail as reported in #1432.
Inheriting from the new backend fixes the issue; logging in with the
deprecated name now works.
Fixes #1432.
From #1435:
CommunicationEventType.category is used also to "detect" order-related
emails, in which case when previewing that email Oscar will put a
user-supplied order in the context for the email template.
This doesn't always work because the string that's saved in category
is localized.
Using choices remedies the problem. I don't think this feature is
commonly used, so no attempt at backwards-compatibility for
non-English setups is made.
South doesn't create a migration for this change.
Fixes #1435.
Registering receivers is a tricky business pre-Django 1.7 as they get
registered at the same time when models get registered, but require the
sending model to already be in the app cache. It's surprising we don't
see more issues!
Recommendations:
* Avoid calls to get_model in modules that get called during app init at
all cost
* Don't use get_model in your own code. Just import directly.
* Switch to Django 1.7 :)
This commit probably fixes the issue in #1205. But get_model calls to
fetch the category, product image and stock record will all fail,
because receivers listen to their signals.
This commit also moves the catalogue receiver into it's own receivers
module, because that's how we do it elsewhere. That won't make a
difference to the issues though.
Correct amount calculation when creating payment events in dashboard
The final line price was calculated as qty * qty * unit price, as the
line price was multiplied with the quantity for a second time. That's no
good.
Reported in #1442. Fixes #1442.
The product status field has been removed since the tables2 PR was made.
Also added the default orderings that are also set in the models Meta
class, which means that the table headers show the applied ordering on
initial load.
e.message has been deprecated since Python 2.6, and doesn't exist in
Python 3. Unfortunately, there's
no good generic way to get an exceptions message; e.g. Django's
VariableDoesNotExist sets e.msg, whereas ValidationError does something
quite complex.
But we rarely use the exception message, and in those cases, a simple
cast to the text type is enough.
Native migrations created with Python 2 differ from ones created with
Python 3. More importantly, they failed when used in Python 3, but not
vice versa. This is caused by field names being marked as byte strings
when using Python 2.
This rewrites the native migrations, which probably isn't a bad thing
either, because they were created with a pre-RC2 version of Django, and
Django 1.7 has since seen a few more migration-related fixes.
It's likely Django now does the correct thing and generates Python 2 and
3 compatible migrations under both versions of Python.
It's not unlikely that a custom deployment would like to change the
title handling. Also adds a more sensible title when editing child
products without a title (instead of showing the parent's title).
This saves one step when customising the product model. Instead, we
dynamically delete the fields not needed for child products -- that's
the cleaner approach anyway.
At the moment, we don't support setting is_discountable for child
products individually. This does keep things simpler when editing
products. If a use case crops up, it should be reasonably easy to
change.
Variant products can now be created from a suitable future parent
product. A helpful message is displayed if the future parent is not
suitable.
Two new paths have been added to handle adding a variant from a suitable
parent, and for adding another variant after saving one.
Some more tweaking was required to pass the tight product validation.
Prevent adding child products to products with stock records
The implicit conversion of a standalone product to a child product only
works if certain conditions are met. As far as I can tell, the only
condition preventing a conversion would be when the product already has
stock records -- parent products aren't allowed to have any.
Beef up ProductCreateView to handle creating child products
A third way to use the view has been added: when called with a parent's
primary key, the view now handles the creation of child products. It
passes the parent into the context, so that both when creating and
editing child products, the template can hide most of the fields.
Implicit product structure: Handle creating and deleting
This is the easy bit. Product structure defaults to standalone product
when creating a product, and reverts to standalone product when the last
child product is deleted.