stephenmcd / cartridge Goto Github PK
View Code? Open in Web Editor NEWEcommerce for Mezzanine
Home Page: http://cartridge.jupo.org
License: BSD 2-Clause "Simplified" License
Ecommerce for Mezzanine
Home Page: http://cartridge.jupo.org
License: BSD 2-Clause "Simplified" License
Hi Stephen,
I'd like to support a strict hierarchy of products. Perhaps an illustration of the desired outcome will explain best.
Here's what the store's left nav and URLs would ideally look like:
My Store /store/
|- Hardware (category) /store/hardware/
|--- Product 1 /store/hardware/product-1/
|--- Product 2 /store/hardware/product-2/
|- Accessories /store/accessories/
|--- Product 3 /store/accessories/product-3/
|--- Product 4 /store/accessories/product-4/
On each product page, I'd like to render the nav bar and breadcrumbs in terms of each product's one (and only) category, ie:
[Home] / [My Store] / [Hardware] / Product 1
Today each product has a ManyToMany relationship to zero or more Categories. I see two ways to support this:
Modify Product.get_absolute_url() to inspect Product.categories to find the Product's canonical category.
When len(self.categories) == 1, return a different view mapped to the URL /<category_slug>/<slug>/
instead of /product/<slug>/
.
Pro:
Con:
Add a new field to Product indicating the "primary" category:
primary_category = models.ForeignKey("Category", _("Primary category"),
blank=True, null=True, on_delete=models.SET_NULL)
Pro:
get_absolute_url
.Con:
Perhaps you have other ideas. I am leaning towards option 1; it could be gated by a feature flag (default off) out of concern for extra DB load.
One other thought: A view serving /<category_slug>/<product_slug>/
should be forgiving in the event that category_slug
does not match the product's category.
Since product_slug
unambiguously identifies the product, the view should issue a 301 redirect to product.get_absolute_url()
. This keeps hierarchical URLs while allowing categories to be renamed/changed in the future.
Hello!
I made a BS3 migration for cartridge, here you can see a demo:
http://test.euve32413.serverloft.de/
One problem left: I don't know why the error messages appears more than one time, please try it out.
If this is ok, I'll love to make a pull request :)
found in cartridge 0.2.1
:)
when i generate PDF, non-latin1 characters are displayed as black boxes. Not yet sure why.
virtualenv package versions are:
Cartridge==0.8.4
Django==1.5.5
Mezzanine==1.4.16
Pillow==2.2.1
argparse==1.2.1
bleach==1.2.2
distribute==0.6.24
filebrowser-safe==0.2.31
grappelli-safe==0.2.23
html5lib==0.95
ipython==1.1.0
oauthlib==0.6.0
pisa==3.0.33
pyPdf==1.13
pytz==2013.8
reportlab==2.7
requests==1.2.3
requests-oauthlib==0.3.3
wsgiref==0.1.2
I created completely localized website in russian, so everything is in russian including product names, product variations and the SHOP_OPTION_TYPE_CHOICES
I entered the following in settings.py:
SHOP_OPTION_TYPE_CHOICES = (
(1, "Размер"),
(2, "Материал"),
)
Everything works fine until I try to create new variations and save the product with new variations in the admin. I press "save" and get DjangoUnicodeDecodeError.
So, somewhere there should be a bug. Hope the traceback below will be enough to indentify it.
Environment: Request Method: POST Request URL: http://localhost:8000/admin/shop/product/9/ Django Version: 1.5.1 Python Version: 2.7.3 Installed Applications: ('mezzanine.boot', 'theme1', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.redirects', 'django.contrib.sessions', 'django.contrib.sites', 'django.contrib.sitemaps', 'django.contrib.staticfiles', 'cartridge.shop', 'mezzanine.conf', 'mezzanine.core', 'mezzanine.generic', 'mezzanine.blog', 'mezzanine.forms', 'mezzanine.pages', 'mezzanine.galleries', 'mezzanine.accounts', 'filebrowser_safe', 'grappelli_safe', 'django.contrib.admin', 'django.contrib.comments') Installed Middleware: ('django.contrib.sessions.middleware.SessionMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.redirects.middleware.RedirectFallbackMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'cartridge.shop.middleware.ShopMiddleware', 'mezzanine.core.request.CurrentRequestMiddleware', 'mezzanine.core.middleware.TemplateForDeviceMiddleware', 'mezzanine.core.middleware.TemplateForHostMiddleware', 'mezzanine.core.middleware.AdminLoginInterfaceSelectorMiddleware', 'mezzanine.core.middleware.SitePermissionMiddleware', 'mezzanine.pages.middleware.PageMiddleware') Traceback: File "/home/dima/.virtualenvs/prj_inox/local/lib/python2.7/site-packages/django/core/handlers/base.py" in get_response 115. response = callback(request, *callback_args, **callback_kwargs) File "/home/dima/.virtualenvs/prj_inox/local/lib/python2.7/site-packages/django/contrib/admin/options.py" in wrapper 372. return self.admin_site.admin_view(view)(*args, **kwargs) File "/home/dima/.virtualenvs/prj_inox/local/lib/python2.7/site-packages/django/utils/decorators.py" in _wrapped_view 91. response = view_func(request, *args, **kwargs) File "/home/dima/.virtualenvs/prj_inox/local/lib/python2.7/site-packages/django/views/decorators/cache.py" in _wrapped_view_func 89. response = view_func(request, *args, **kwargs) File "/home/dima/.virtualenvs/prj_inox/local/lib/python2.7/site-packages/django/contrib/admin/sites.py" in inner 202. return view(request, *args, **kwargs) File "/home/dima/.virtualenvs/prj_inox/local/lib/python2.7/site-packages/django/utils/decorators.py" in _wrapper 25. return bound_func(*args, **kwargs) File "/home/dima/.virtualenvs/prj_inox/local/lib/python2.7/site-packages/django/utils/decorators.py" in _wrapped_view 91. response = view_func(request, *args, **kwargs) File "/home/dima/.virtualenvs/prj_inox/local/lib/python2.7/site-packages/django/utils/decorators.py" in bound_func 21. return func(self, *args2, **kwargs2) File "/home/dima/.virtualenvs/prj_inox/local/lib/python2.7/site-packages/django/db/transaction.py" in inner 223. return func(*args, **kwargs) File "/home/dima/.virtualenvs/prj_inox/local/lib/python2.7/site-packages/django/contrib/admin/options.py" in change_view 1107. change_message = self.construct_change_message(request, form, formsets) File "/home/dima/.virtualenvs/prj_inox/local/lib/python2.7/site-packages/django/contrib/admin/options.py" in construct_change_message 696. 'object': force_text(changed_object)}) File "/home/dima/.virtualenvs/prj_inox/local/lib/python2.7/site-packages/django/utils/encoding.py" in force_text 115. raise DjangoUnicodeDecodeError(s, *e.args) Exception Type: DjangoUnicodeDecodeError at /admin/shop/product/9/ Exception Value: 'ascii' codec can't decode byte 0xd0 in position 0: ordinal not in range(128). You passed in ()
With a clean install of Cartridge I can go to shop, add the Django Pony, checkout, add Billing Details, uncheck "My delivery details are the same as my billing details" add custom delivery details, and it will show the correct items in the "POST" request on the next page but then it reverts all items in shipping_details to the same as billing_details. Something on the server is simply using billing details as shipping no matter what.
Looks like commit 832032f broke south migration 0001:
$ manage.py migrate
[...]
File "/home/ubuntu/.virtualenvs/pkb/local/lib/python2.7/site-packages/South-0.7.6-py2.7.egg/south/migration/migrators.py", line 175, in _run_migration
migration_function()
File "/home/ubuntu/.virtualenvs/pkb/local/lib/python2.7/site-packages/South-0.7.6-py2.7.egg/south/migration/migrators.py", line 57, in <lambda>
return (lambda: direction(orm))
File "/home/ubuntu/.virtualenvs/pkb/local/lib/python2.7/site-packages/Cartridge-0.8.1-py2.7.egg/cartridge/shop/migrations/0001_initial.py", line 233, in forwards
from cartridge.shop.management import create_initial_product
ImportError: cannot import name create_initial_product
Maybe just a matter of renaming the method, though IMO it'd be better still to avoid sneaking this hook into the migration (introduced in 52fa3f7). In addition to making the migration brittle to external changes as above, the forced prompt interferes with non-interactive migrate
(deployment scripts, continuous builds, etc).
Small bug in Order.complete():
https://github.com/stephenmcd/cartridge/blob/master/cartridge/shop/models.py#L474-L501
The fields from self.session_fields are deleted at the top of the function, but we don't get the discount_code out of the session until later in the function - and discount code is one of those deleted as it's listed in self.session_fields.
This way, the uses_remaining field is never decremented when the discount code is used, as it will always be None.
Simple enough to fix by some rearrangement of lines in the function.
Warning at /admin/shop/sale/2/
Data truncated for column 'sale_price_aud' at row 59
in shop/models.py: Sale.save:
for priced_objects in (products, variations):
priced_objects.filter(**extra_filter).update(sale_id=self.id,
sale_to=self.valid_to, sale_from=self.valid_from,
sale_price=sale_price)
Right now, the order receipt template file name is hard-coded into checkout.py. I'd like to have a setting like the one for payment handler for the receipt handler.
While trying to delete image for a product, a validation error is thrown from the save_formset method in ProductAdmin. I have somewhat modified the cartridge code, but was able to replicate this error on the cartridge demo site admin as well.
When I want to view a product with a lot of product variants (about 1000) and caching with memcached is enabled I get this error:
[04/Jun/2013 14:59:31] ERROR [django.request:212] Internal Server Error: /shop/product/зигзаг-полотенцесушитель/ Traceback (most recent call last): File "/home/inox-t/.virtualenvs/prj_inox/lib/python2.6/site-packages/django/core/handlers/base.py", line 187, in get_response response = middleware_method(request, response) File "/home/inox-t/.virtualenvs/prj_inox/lib/python2.6/site-packages/mezzanine/core/middleware.py", line 134, in process_response response.add_post_render_callback(_cache_set) File "/home/inox-t/.virtualenvs/prj_inox/lib/python2.6/site-packages/django/template/response.py", line 92, in add_post_render_callback callback(self) File "/home/inox-t/.virtualenvs/prj_inox/lib/python2.6/site-packages/mezzanine/core/middleware.py", line 132, in _cache_set = lambda r: cache_set(cache_key, r.content, timeout) File "/home/inox-t/.virtualenvs/prj_inox/lib/python2.6/site-packages/mezzanine/utils/cache.py", line 37, in cache_set return cache.set(_hashed_key(key), packed, real_timeout) File "/home/inox-t/.virtualenvs/prj_inox/lib/python2.6/site-packages/django/core/cache/backends/memcached.py", line 71, in set self._cache.set(key, value, self._get_memcache_timeout(timeout)) ServerError: error 10 from memcached_set: SERVER ERROR
here my cache settings:
CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache', 'LOCATION': '127.0.0.1:11211', "BINARY" : True, 'OPTIONS': { # Maps to pylibmc "behaviors" 'tcp_nodelay': True, 'ketama': True, } } } PYLIBMC_MIN_COMPRESS_LEN=2048
I googled a bit about this error... it seems it is related to 1M limit of memcached value.
I tried with PYLIBMC_MIN_COMPRESS_LEN set and without it, same results
Recent change to mezzanine.utils.conf requires additional options in cartridge project template.
python manage.py syncdb
Error: One or more models did not validate:
shop.product: "unit_price": DecimalFields require a "max_digits" attribute value that is greater than the value of the "decimal_places" attribute.
shop.product: "sale_price": DecimalFields require a "max_digits" attribute value that is greater than the value of the "decimal_places" attribute.
shop.productvariation: "unit_price": DecimalFields require a "max_digits" attribute value that is greater than the value of the "decimal_places" attribute.
shop.productvariation: "sale_price": DecimalFields require a "max_digits" attribute value that is greater than the value of the "decimal_places" attribute.
shop.order: "shipping_total": DecimalFields require a "max_digits" attribute value that is greater than the value of the "decimal_places" attribute.
shop.order: "item_total": DecimalFields require a "max_digits" attribute value that is greater than the value of the "decimal_places" attribute.
shop.order: "discount_total": DecimalFields require a "max_digits" attribute value that is greater than the value of the "decimal_places" attribute.
shop.order: "total": DecimalFields require a "max_digits" attribute value that is greater than the value of the "decimal_places" attribute.
shop.cartitem: "unit_price": DecimalFields require a "max_digits" attribute value that is greater than the value of the "decimal_places" attribute.
shop.cartitem: "total_price": DecimalFields require a "max_digits" attribute value that is greater than the value of the "decimal_places" attribute.
shop.orderitem: "unit_price": DecimalFields require a "max_digits" attribute value that is greater than the value of the "decimal_places" attribute.
shop.orderitem: "total_price": DecimalFields require a "max_digits" attribute value that is greater than the value of the "decimal_places" attribute.
shop.sale: "discount_deduct": DecimalFields require a "max_digits" attribute value that is greater than the value of the "decimal_places" attribute.
shop.sale: "discount_exact": DecimalFields require a "max_digits" attribute value that is greater than the value of the "decimal_places" attribute.
shop.discountcode: "discount_deduct": DecimalFields require a "max_digits" attribute value that is greater than the value of the "decimal_places" attribute.
shop.discountcode: "discount_exact": DecimalFields require a "max_digits" attribute value that is greater than the value of the "decimal_places" attribute.
shop.discountcode: "min_purchase": DecimalFields require a "max_digits" attribute value that is greater than the value of the "decimal_places" attribute.
Freshy installed from scratch following the installation guide.
python manage.py createdb fails as follows.
/usr/src/cartridge-env/lib/python2.7/site-packages/mezzanine/utils/conf.py:48: UserWarning: You haven't defined the ALLOWED_HOSTS settings, which Django 1.5 requires. Will fall back to the domains configured as sites.
warn("You haven't defined the ALLOWED_HOSTS settings, which "
Traceback (most recent call last):
File "manage.py", line 28, in <module>
execute_from_command_line(sys.argv)
File "/usr/src/cartridge-env/lib/python2.7/site-packages/django/core/management/__init__.py", line 453, in execute_from_command_line
utility.execute()
File "/usr/src/cartridge-env/lib/python2.7/site-packages/django/core/management/__init__.py", line 392, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "/usr/src/cartridge-env/lib/python2.7/site-packages/django/core/management/__init__.py", line 272, in fetch_command
klass = load_command_class(app_name, subcommand)
File "/usr/src/cartridge-env/lib/python2.7/site-packages/django/core/management/__init__.py", line 77, in load_command_class
module = import_module('%s.management.commands.%s' % (app_name, name))
File "/usr/src/cartridge-env/lib/python2.7/site-packages/django/utils/importlib.py", line 35, in import_module
__import__(name)
File "/usr/src/cartridge-env/lib/python2.7/site-packages/mezzanine/core/management/__init__.py", line 12, in <module>
from mezzanine.utils.tests import copy_test_to_media
File "/usr/src/cartridge-env/lib/python2.7/site-packages/mezzanine/utils/tests.py", line 10, in <module>
from mezzanine.conf import settings
File "/usr/src/cartridge-env/lib/python2.7/site-packages/mezzanine/conf/__init__.py", line 140, in <module>
module = import_module(app)
File "/usr/src/cartridge-env/lib/python2.7/site-packages/django/utils/importlib.py", line 35, in import_module
__import__(name)
ImportError: No module named shop
How about to add an image field for Category, which may be used for displaying in category list or brand list?
Easiest reproduction:
SHOP_CART_EXPIRY_MINUTES
.At this point, no-one will be able to buy any Foos anymore, unless you trigger cache cleanup in some way. But the cache cleanup is triggered during CartManager.from_request
only when there is another session containing a cart reference. In the above mentioned scenario, no one contains such a reference anymore after step 3, making the cached cart item stuck in limbo, and can neither be accessed nor deleted.
The relevant source (cartridge/shop/manages.py
, line 25 to 34)
if cart_id:
try:
cart = self.get(last_updated__gte=expiry_time, id=cart_id)
except self.model.DoesNotExist:
request.session["cart"] = None
else:
# Update timestamp and clear out old carts.
cart.last_updated = n
cart.save()
self.filter(last_updated__lt=expiry_time).delete()
Is there a reason why the current implementation is like this? I feel that you can clean caches even when you don't create a new cache item
if cart_id:
try:
cart = self.get(last_updated__gte=expiry_time, id=cart_id)
except self.model.DoesNotExist:
request.session["cart"] = None
else:
# Update timestamp and clear out old carts.
cart.last_updated = n
cart.save()
self.filter(last_updated__lt=expiry_time).delete()
Or is there anything I missed?
Is this the intended functionality? If not, it is an easy enough fix I can submit it in no-time.
However, my shop has three hundred thousand (300,000) different products, of which only 6,000 are available at a given time. This means that the user has to wade through hundreds of thousands of products to find ones that they can even buy.
I can submit a patch to dynamically specify the behavior based on a setting, as an alternative.
Working on this right now...
Hey,
the order will be saved with the last step with a post request, but external payment services don't send a post request when returning to the site. In repository cartridge-payments (https://github.com/explodes/cartridge-payments) it's solved by saving the order in the penultimate step.
But if I abort the order in paypal (for example), the order is still saved.
I suggest to move the saving-code to the complete-function and make it only visible after visited step 3. A session variable could make sure to save and send email just one time.
What do you think?
hello,
this morning i installed mezzanine and cartridge ( from github)
mezzanine started ok presenting the default page on the browser.
howerver, in a second project directory, using mezzanine and cartridge, the following error occurred.
i also noticed that the the database configuration entries in settings.py were ignored.
the full error and trace message is a here https://gist.github.com/961875
regards
john
the host is gentoo linux with python 2.7.
ImportError at /
cannot import name DynamicInlineAdmin
Request Method: GET
Request URL: http://blackhole:9876/
Django Version: 1.3
Exception Type: ImportError
Exception Value:
cannot import name DynamicInlineAdmin
Exception Location: /usr/lib/python2.7/site-packages/Cartridge-0.2-py2.7.egg/cartridge/shop/admin.py in , line 8
Python Executable: /usr/bin/python2.7
Python Version: 2.7.1
Python Path:
['../../../mezzanine',
'../../../mezzanine',
'/home/john/projects/kmbooks',
'/usr/lib/python2.7/site-packages/setuptools-0.6c12dev_r85381-py2.7.egg',
'/usr/lib/python2.7/site-packages/DateTime-2.12.6-py2.7.egg',
'/usr/lib/python2.7/site-packages/pytz-2010o-py2.7.egg',
'/usr/lib/python2.7/site-packages/zope.interface-3.6.1-py2.7-linux-i686.egg',
'/usr/lib/python2.7/site-packages/hmac-20101005-py2.7.egg',
'/usr/lib/python2.7/site-packages/hashlib-20081119-py2.7-linux-i686.egg',
'/usr/lib/python2.7/site-packages/BeautifulSoup-3.2.0-py2.7.egg',
'/usr/lib/python2.7/site-packages/CherryPy-3.1.2-py2.7.egg',
'/usr/lib/python2.7/site-packages/ClientForm-0.2.10-py2.7.egg',
'/usr/lib/python2.7/site-packages/yolk-0.4.1-py2.7.egg',
'/usr/lib/python2.7/site-packages/distribute-0.6.14-py2.7.egg',
'/usr/lib/python2.7/site-packages/pythonutils',
'/usr/lib/python2.7/site-packages/configobj-4.7.0-py2.7.egg',
'/usr/lib/python2.7/site-packages/PathUtils-0.8.2-py2.7.egg',
'/usr/lib/python2.7/site-packages/odict-1.4.1-py2.7.egg',
'/usr/lib/python2.7/site-packages/pywsgi-0.9.0-py2.7.egg',
'/usr/lib/python2.7/site-packages/imap_utils-0.4-py2.7.egg',
'/usr/lib/python2.7/site-packages/IMAPClient-0.6.2-py2.7.egg',
'/usr/lib/python2.7/site-packages/IMDbPY-4.6-py2.7-linux-i686.egg',
'/usr/lib/python2.7/site-packages/lxml-2.3beta1-py2.7-linux-i686.egg',
'/usr/lib/python2.7/site-packages/sqlalchemy_migrate-0.6-py2.7.egg',
'/usr/lib/python2.7/site-packages/SQLAlchemy-0.6.5-py2.7.egg',
'/usr/lib/python2.7/site-packages/SQLObject-0.16dev_r4327-py2.7.egg',
'/usr/lib/python2.7/site-packages/Tempita-0.5dev-py2.7.egg',
'/usr/lib/python2.7/site-packages/decorator-3.2.1-py2.7.egg',
'/usr/lib/python2.7/site-packages/FormEncode-1.2.3dev-py2.7.egg',
'/usr/lib/python2.7/site-packages/threadpool-1.2.7-py2.7.egg',
'/usr/lib/python2.7/site-packages/pip-0.8.2-py2.7.egg',
'/usr/lib/python2.7/site-packages/grappelli_safe-0.1.5-py2.7.egg',
'/usr/lib/python2.7/site-packages/filebrowser_safe-0.1.1-py2.7.egg',
'/usr/lib/python2.7/site-packages/Mezzanine-0.11-py2.7.egg',
'/usr/lib/python2.7/site-packages/Cartridge-0.2-py2.7.egg',
'/usr/lib/python2.7',
'/usr/lib/python27.zip',
'/usr/lib/python2.7/plat-linux2',
'/usr/lib/python2.7/lib-tk',
'/usr/lib/python2.7/lib-old',
'/usr/lib/python2.7/lib-dynload',
'/usr/lib/python2.7/site-packages',
'/usr/lib/python2.7/site-packages/FontTools',
'/usr/lib/python2.7/site-packages/PIL',
'/usr/lib/python2.7/site-packages/gtk-2.0',
'/usr/lib/python2.7/site-packages/setuptools-0.6c11-py2.7.egg-info',
'/usr/lib/portage/pym']
Server time: Mon, 9 May 2011 10:54:13 +1000
I get asked the question "Would you like to install an initial Category and Product? (yes/no)" on almost every manage.py
command I use, test, migrate, etc etc. This should probably only happen on syncdb/createdb.
Hi everybody,
I have the following MySQL error when working on a Sale object in cartridge:
(1093, "You can't specify target table 'shop_product' for update in FROM clause")
It looks like if it is the same error mentioned in the following post:
https://groups.google.com/forum/?fromgroups=#!topic/mezzanine-users/lD0JiWN3HL4
The issue occurs when trying to save a new Sale object with Active as True or setting Active as True on an existing Sale object.
(Sale with at least 1 category selected and discount in either percent of fixed value).
I have created a new fresh install according to the doc just to test it again but the problem occurs again.
It occurs also when creating initial category and Product during DB creation:
https://groups.google.com/forum/?fromgroups=#!searchin/mezzanine-users/1093/mezzanine-users/_BCXzBZqb1s/Kzo4KDwjqooJ
But still the error occurs when setting a Sale to True even if no initial data are created.
shop.models.Sale actually mentions MySQL errors so it looked liked it has been fixed already but I still got the error.
ubuntu 10.04
Python 2.6.5
virtualenv-1.7.1.2
Cartridge-0.6.0
Mezzanine-1.2.4
Mysql_python-1.2.4
For now I have switched to Postgresql and everything is working fine.
Thanks!
David
Hi,
Upgrade to latest Mezzanine, 1.1.3.
Ran into an error when doing the following in Cartridge:
Stacktrace:
http://dpaste.com/764168/
The product template is loading /js/jquery.tools.js and this was refactored out of mezzanine.
cartridge/shop/templates/shop/product.html:
<script src="{{ STATIC_URL }}mezzanine/js/jquery.tools.js"></script>The breadcrumb on the default theme, for the shop/product/... is broken, also on the demo
Affected version 0.5
test url: http://127.0.0.1:8000/shop/product/django-pony/
I created completely localized website in russian, so everything is in russian including product names, product variations etc..
Wher adding a product to the shopping cart (with one variation, which is in russian too) I get the error (below).
And here the SQL statement (from PostgreSQL logs, below).
Probably the "url" field is too short, probably because of this translation Unicode->%D0%B8
The quick fix could be just increasing the field length.
Hint: may be such kilometer long urls make not so much sense... is there an easy way to install a custom "encoding" function?. I mean to translate the product name "Полоски вертикальные, полотенцесушитель" to url "poloski-vertikalnie-polotenzesushitel" (this is so called "translit", a special way to write in russian using latine alphabet, there are enough functions to do this translation, I'm asking about a possibility to plug-in such function into Cartridge. I want to edit products in Admin and get the urls in Latine/english automatically)
2013-06-03 01:07:20 EEST 0 LOG: statement: BEGIN 2013-06-03 01:07:20 EEST 0 LOG: duration: 0.049 ms 2013-06-03 01:07:20 EEST 0 LOG: statement: SELECT (1) AS "a" FROM "shop_cartitem" WHERE "shop_cartitem"."id" = 57 LIMIT 1 2013-06-03 01:07:20 EEST 0 LOG: duration: 0.187 ms 2013-06-03 01:07:20 EEST 0 LOG: statement: UPDATE "shop_cartitem" SET "sku" = '96', "description" = 'Полоски вертикальные, полотенцесушитель Размер, мм: 500x600', "quantity" = 1, "unit_price" = '1900.00', "total_price" = '1900.00', "cart_id" = 38, "url" = '/shop/product/%D0%BF%D0%BE %D0%BB%D0%BE%D1%81%D0%BA%D0%B8-%D0%B2%D0%B5%D1%80%D1%82%D0%B8%D0%BA%D0%B0%D0%BB%D1%8C%D0%BD%D1%8B%D0%B5-%D0%BF%D0%BE%D0%BB%D0%BE%D1%82%D0%B5%D 0%BD%D1%86%D0%B5%D1%81%D1%83%D1%88%D0%B8%D1%82%D0%B5%D0%BB%D1%8C/', "image" = 'product/DSC02493.jpg' WHERE "shop_cartitem"."id" = 57 2013-06-03 01:07:20 EEST 0 ERROR: value too long for type character varying(200) 2013-06-03 01:07:20 EEST 0 STATEMENT: UPDATE "shop_cartitem" SET "sku" = '96', "description" = 'Полоски вертикальные, полотенцесушитель Разме р, мм: 500x600', "quantity" = 1, "unit_price" = '1900.00', "total_price" = '1900.00', "cart_id" = 38, "url" = '/shop/product/%D0%BF%D0%BE%D0%B B%D0%BE%D1%81%D0%BA%D0%B8-%D0%B2%D0%B5%D1%80%D1%82%D0%B8%D0%BA%D0%B0%D0%BB%D1%8C%D0%BD%D1%8B%D0%B5-%D0%BF%D0%BE%D0%BB%D0%BE%D1%82%D0%B5%D0%BD% D1%86%D0%B5%D1%81%D1%83%D1%88%D0%B8%D1%82%D0%B5%D0%BB%D1%8C/', "image" = 'product/DSC02493.jpg' WHERE "shop_cartitem"."id" = 57 2013-06-03 01:07:20 EEST 0 LOG: statement: ROLLBACK
Environment: Request Method: POST Request URL: http://localhost:8000/shop/product/%D0%BF%D0%BE%D0%BB%D0%BE%D1%81%D0%BA%D0%B8-%D0%B2%D0%B5%D1%80%D1%82%D0%B8%D0%BA%D0%B0%D0%BB%D1%8C%D0%BD%D1%8B%D0%B5-%D0%BF%D0%BE%D0%BB%D0%BE%D1%82%D0%B5%D0%BD%D1%86%D0%B5%D1%81%D1%83%D1%88%D0%B8%D1%82%D0%B5%D0%BB%D1%8C/ Django Version: 1.5.1 Python Version: 2.7.3 Installed Applications: ('mezzanine.boot', 'theme1', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.redirects', 'django.contrib.sessions', 'django.contrib.sites', 'django.contrib.sitemaps', 'django.contrib.staticfiles', 'cartridge.shop', 'mezzanine.conf', 'mezzanine.core', 'mezzanine.generic', 'mezzanine.blog', 'mezzanine.forms', 'mezzanine.pages', 'mezzanine.galleries', 'mezzanine.accounts', 'filebrowser_safe', 'grappelli_safe', 'django.contrib.admin', 'django.contrib.comments') Installed Middleware: ('django.contrib.sessions.middleware.SessionMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.redirects.middleware.RedirectFallbackMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'cartridge.shop.middleware.ShopMiddleware', 'mezzanine.core.request.CurrentRequestMiddleware', 'mezzanine.core.middleware.TemplateForDeviceMiddleware', 'mezzanine.core.middleware.TemplateForHostMiddleware', 'mezzanine.core.middleware.AdminLoginInterfaceSelectorMiddleware', 'mezzanine.core.middleware.SitePermissionMiddleware', 'mezzanine.pages.middleware.PageMiddleware') Traceback: File "/home/dima/.virtualenvs/prj_inox/local/lib/python2.7/site-packages/django/core/handlers/base.py" in get_response 109. response = middleware_method(request, callback, callback_args, callback_kwargs) File "/home/dima/.virtualenvs/prj_inox/local/lib/python2.7/site-packages/mezzanine/pages/middleware.py" in process_view 71. response = view_func(request, *view_args, **view_kwargs) File "/home/dima/.virtualenvs/prj_inox/local/lib/python2.7/site-packages/cartridge/shop/views.py" in product 58. request.cart.add_item(add_product_form.variation, quantity) File "/home/dima/.virtualenvs/prj_inox/local/lib/python2.7/site-packages/cartridge/shop/utils.py" in add_item 47. cart.add_item(*args, **kwargs) File "/home/dima/.virtualenvs/prj_inox/local/lib/python2.7/site-packages/cartridge/shop/models.py" in add_item 555. item.save() File "/home/dima/.virtualenvs/prj_inox/local/lib/python2.7/site-packages/cartridge/shop/models.py" in save 638. super(SelectedProduct, self).save(*args, **kwargs) File "/home/dima/.virtualenvs/prj_inox/local/lib/python2.7/site-packages/django/db/models/base.py" in save 546. force_update=force_update, update_fields=update_fields) File "/home/dima/.virtualenvs/prj_inox/local/lib/python2.7/site-packages/django/db/models/base.py" in save_base 626. rows = manager.using(using).filter(pk=pk_val)._update(values) File "/home/dima/.virtualenvs/prj_inox/local/lib/python2.7/site-packages/django/db/models/query.py" in _update 591. return query.get_compiler(self.db).execute_sql(None) File "/home/dima/.virtualenvs/prj_inox/local/lib/python2.7/site-packages/django/db/models/sql/compiler.py" in execute_sql 1014. cursor = super(SQLUpdateCompiler, self).execute_sql(result_type) File "/home/dima/.virtualenvs/prj_inox/local/lib/python2.7/site-packages/django/db/models/sql/compiler.py" in execute_sql 840. cursor.execute(sql, params) File "/home/dima/.virtualenvs/prj_inox/local/lib/python2.7/site-packages/django/db/backends/util.py" in execute 41. return self.cursor.execute(sql, params) File "/home/dima/.virtualenvs/prj_inox/local/lib/python2.7/site-packages/django/db/backends/postgresql_psycopg2/base.py" in execute 58. six.reraise(utils.DatabaseError, utils.DatabaseError(*tuple(e.args)), sys.exc_info()[2]) File "/home/dima/.virtualenvs/prj_inox/local/lib/python2.7/site-packages/django/db/backends/postgresql_psycopg2/base.py" in execute 54. return self.cursor.execute(query, args) Exception Type: DatabaseError at /shop/product/полоски-вертикальные-полотенцесушитель/ Exception Value: value too long for type character varying(200)
I am not entirely sure if this is a bug in mezzanine or cartridge, but either way I am running out of PEBKAC to blame (I think!).
A single mezzanine project with two sites, foo.local and bar.local. bar.local is a CNAME for foo.local. Both hosts served via nginx/uwsgi.
Visiting http://bar.local/shop/product/product1 should display the product page, while http://foo.local/shop/product/product1 should return a 404.
The product page is visible at both URLs.
Following these steps yields the expected result, that is, the product page is only visible on the host bar.local.
pip freeze:
Cartridge==0.8.4
Django==1.5.4
Mezzanine==1.4.16
MySQL-python==1.2.4
Pillow==2.2.1
argparse==1.2.1
bleach==1.2.2
django-appconf==0.6
django-compressor==1.3
filebrowser-safe==0.2.31
grappelli-safe==0.2.22
html5lib==0.95
oauthlib==0.6.0
pisa==3.0.33
python-memcached==1.53
pytz==2013.7
requests==1.2.3
requests-oauthlib==0.3.3
setproctitle==1.1.7
six==1.4.1
wsgiref==0.1.2
Stephen,
For automated deployment, I need a way to disable the default category and product installation for the demonstration store. Look for a setting in settings.py, else ask the user if interactive, else do not install demo data is what the patch below implements. I can submit a pull request, but there are a couple of different ways to nest the conditional logic, so wanted to get your comments first.
Regards,
Brian
This issue is similar to the Mezzanine issue #222.
stephenmcd/mezzanine#222
Committed fix in my fork:
https://github.com/nimbis/cartridge/commit/20474376662790a4e3d2f50f97ed8c9137e15063
diff --git a/cartridge/shop/management/__init__.py b/cartridge/shop/management/__init__.py
index f671f2f..eae1747 100644
--- a/cartridge/shop/management/__init__.py
+++ b/cartridge/shop/management/__init__.py
@@ -11,7 +11,9 @@ from cartridge.shop import models as shop_app
def create_initial_product(app, created_models, verbosity, **kwargs):
if settings.DEBUG and Product in created_models:
- if kwargs.get("interactive"):
+ if not getattr(settings, 'CARTRIDGE_INSTALL_INITIAL_CONTENT', False):
+ return
+ elif kwargs.get("interactive"):
confirm = raw_input("\nWould you like to install an initial "
"Category and Product? (yes/no): ")
while True:
@@ -20,6 +22,8 @@ def create_initial_product(app, created_models, verbosity, **kwargs):
elif confirm == "no":
return
confirm = raw_input("Please enter either 'yes' or 'no': ")
+ else:
+ return
if verbosity >= 1:
print
print "Creating initial Category and Product ..."
Hi Stephen.
I am pretty sure the exception handling in cartridge/shop/models.py Sale.save() is incorrect.
except OperationalError:
# Work around for MySQL which does not allow update
# to operate on subquery where the FROM clause would
# have it operate on the same table.
#
# http://dev.mysql.com/
# doc/refman/5.0/en/subquery-errors.html
try:
for priced in priced_objects.filter(**extra_filter):
for field, value in update.items():
setattr(priced, field, value)
priced.save() <- save throw an Exception
except Warning:
pass
except Warning:
pass
Currently if the priced.save() throws an exception the out loop will not complete and the any product/variation that have not been process won't be updated. It would be better to put the exception handling right around the save call, ie:
try:
priced.save()
except Warning:
pass
Of course I could be wrong. Thanks for you time.
Regards,
Damian
On a fresh Cartridge install (0.8.2) included in a existing Mezzanine project, I had the following error when asking to the pdf invoice version :
ImportError at /shop/invoice/2/
No module named reportlab.lib.units
Request Method: GET
Request URL: http://localhost:8000/shop/invoice/2/?format=pdf
Django Version: 1.5.1
Exception Type: ImportError
Exception Value: No module named reportlab.lib.units
To fix a the issue, I just had to do :
pip install reportlab
Did I miss something or is the dependency missing in the python egg ?
regards,
Luc
The current discount code feature allows a reduction in price/percentage on a per-item basis for selected products/categories, and also allows you to limit how many times the code is used with 'uses_remaining'.
However, the uses_remaining field is only decremented by 1 at the end of an order, even if the code was used for multiple items.
For example, if I create a code 5OFF to give $5 off each item in an order, but limit it to 2 uses only, a user can still order 3 or more items (either multiple of the same, or different items) and get $5 off each one, even though technically the code should only apply to the first two items.
Is the currently behaviour the intended behaviour? Or should we fix this so that 'uses_remaining' applies to the number of items the code applies to?
In some scenarios, the customer himself needs to insert additional information, which is nearly impossible to predict, so the CharField text input is needed.
Is there any plans to implement this kind of functionality?
Thank You
Hi,
I hope you don't mind newbie questions. I am trying to set up and configure the main url to be the shop page. I checked out the code and saw that category.html was use as a page template. I am not sure what points to it. And I see the blog example from Mezzanine in the url.py to point to blog. I tired similar setting for the url for shop but I still could not get it right. Is there an example I can look at to do that simple setting? How could I set shop link to be the main home page and blog link to be secondary link? Thank you for your help.
Watt Poosanguansit
The shop order only supports a single discount code, but depending on the behaviour of the discount codes it is possible for a user to apply more than one.
Application of a second discount code should cancel the first.
For example:
I created two discount codes - FREESHIP gave free shipping, and 5OFF gave $5 off any item.
If I apply one and then the other, both would take effect - giving the user $5 off each item /and/ free shipping. However, as only one code is stored with the order, the uses_remaining of the one applied second would be decremented, but not the first.
Either only a single discount code should apply (so when the second is applied, the first's effect is cancelled) or we may have to think about how to apply multiple codes to the cart/order.
Uploading a big product image (image heigh > screen height) works.
Reduced image, 199x300 px displayed on product page, that's OK
When I click on the image, the original (big) image displayed over the product page. It doesn't fit on the screen, browser shows vertical scrollbar. Perfect.
Now when I try to scroll, the background (product) page is moving, not the image!
There is no way to see the lower part of the big image.
I tested on the demo on http://mezzanine.jupo.org/
The dropdown list with product variations on the product page is unsorted. I have product variations which are numbers, so it is not a localization or NLS issue (the site is in russian)
Attached a picture of dropdown list and a picture from admin showing product options (properly sorted when I click on "name" column header)
On the product description page /shop/product// if we add a quantity more than the available stock it just refreshes the page. Need to inform the user that the quantity added is not valid (This is already done on the /shop/cart page so i think it will be fairly easy to port the changes on to this page as well)
Hi,
I know this isn't really a bug report and I apologize for it. Please feel free to close this issue. I just wanted to contact you about the next release. I find the optional wishlist feature controlled by the SHOP_USE_WISHLIST setting very useful, but it's only available from the git version. I'm deploying my webapp on Openshift and would really like to be able to use a released version. Thank you!
There are two instances of the class Product in the models.py. The newest one appears to be the second one defined, so the issue is not being seen.
Assume a user has entered a discount code in their cart.
When they go to the checkout, the discount code form field (under the address info) is populated with the discount code used in their previous order, and not with the discount code from the session.
I also believe that the discount code field should /never/ be populated from a previous order, even when that code is still valid.
Small modification to OrderForm.init():
if initial is not None:
initial["step"] = step
code = request.session.get('discount_code', None)
initial["discount_code"] = code
With the settings SHOP_CHECKOUT_FORM_CLASS, user might be removing some of the fields such as the cc in their custom checkout form. This would raise KeyError when cartridge try to remove the field in the session:-
--- a/cartridge/shop/views.py +++ b/cartridge/shop/views.py @@ -192,7 +192,8 @@ def checkout_steps(request): sensitive_card_fields = ("card_number", "card_expiry_month", "card_expiry_year", "card_ccv") for field in sensitive_card_fields: - del request.session["order"][field] + if field in request.session["order"]: + del request.session["order"][field] # FIRST CHECKOUT STEP - handle shipping and discount code. if step == checkout.CHECKOUT_STEP_FIRST:
Hi,
I'm currently working on a recipe-sharing project. It has a similar model structure with Cartridge: A Displayable subclass for recipe, and a category page model to show a list of recipes. Cartridge works fine with it, of course, but I'm facing a little problem on admin customization — Cartridge's category model is named Category
(with verbose names "Category/Categories"), and shows up in the Page admin's add menu as "Category," which to me sounds a bit too generic than it should. Of course, you can get what you want once you understands this, but still it might confuses people not familiar with Cartridge (and/or Mezzanine), which is not good since a CMS admin is supposed to be usable for non-programmers as well. Even programmers might need to spend some unneeded brain power trying to resolve between different kinds of categories if they have a more complicated structure.
So basically I'm purposing a change of name for model Category
. It'd be good just changing the verbose names to Product category/categories. Refactoring model names would be more work, and you can always work around it by using from cartridge.shop.models import Category as ProductCategory
if you need to (do you ever?).
Any thoughts?
shop/product.html lacks the richtext_filter tag, so markdown doesn't get rendered as it should be.
Change from:
{{ product.content|safe }}
to:
{{ product.content|richtext_filter|safe }}
On the shop/cart page, If we specify the quantity as 0 and Click "Update Cart" the price is updated but ideally this product should be removed from the shopping basket.
Since this is not removed at the moment, it ends up in the invoice.
I'm building a site using Mezzanine + Cartridge and would like to one way or another implement a reservation system / booking tool using Cartridge.
Does someone already have anything like this or any experiences / opinions on whether the Cartridge data model would bend to this kind of product? In this case I would be using it for a cottage reservation system, so customers need to be able to reserve cottages for a variable amount of night and also select extra products (sheets, breakfast, etc).
Thanks for any tips!
I noticed that if you set SHOP_CHECKOUT_ACCOUNT_REQUIRED to True in your settings you get a no reverse match at /shop/checkout/. This can be fixed by changing reverse("shop_CHECKOUT") to reverse("shop_checkout") on line 216 of cartridge.shop.views.
It stops after 'Creating table shop_product' and throws some errors, the last of which is this:
File "(mypath)/django/db/backends/postgresql_psycopg2/base.py", line 44, in execute return self.cursor.execute(query, args) django.db.utils.DatabaseError: NUMERIC scale 127 must be between 0 and precision 10
I'm guessing it has something to do with an Integer field in the cartridge model, but I'm not sure which one. I'm running Mezzanine .8 runs just fine without Cartridge. So this issue is isolated to setting up a Cartridge project.
On /shop/checkout occasionally my users are getting an error. The error log shows this in the traceback:
Traceback (most recent call last):
File "/virtualenv/lib/python2.6/site-packages/Django-1.3-py2.6.egg/django/core/handlers/base.py", line 111, in get_response
response = callback(request, _callback_args, *_callback_kwargs)
File "/virtualenv/src/cartridge/cartridge/shop/views.py", line 306, in checkout_steps
form = OrderForm(request, step, initial=initial, data=data)
File "/virtualenv/src/cartridge/cartridge/shop/forms.py", line 304, in init
if data is not None and int(data["step"]) != step:
File "/virtualenv/lib/python2.6/site-packages/Django-1.3-py2.6.egg/django/utils/datastructures.py", line 256, in getitem
raise MultiValueDictKeyError("Key %r not found in %r" % (key, self))
MultiValueDictKeyError: "Key 'step' not found in <QueryDict: {u'shipping_detail_country': [u'USA'], u'card_ccv': [u'xxx'], u'additional_instructions': [u''], u'billing_detail_city': [u'Las Vegas'], u'billing_detail_country': [u'USA'], u'shipping_detail_phone': [u'xxx-xxx-xxxx'], u'shipping_detail_city': [u'Las Vegas'], u'shipping_detail_postcode': [u'46714'], u'billing_detail_phone': [u'xxx-xxx-xxxx'], u'shipping_detail_last_name': [u'xxxx'], u'card_expiry_month': [u'xx'], u'billing_detail_street': [u'xxxx'], u'shipping_detail_first_name': [u'xxx'], u'billing_detail_last_name': [u'xxx'], u'card_expiry_year': [u'xxxx'], u'csrfmiddlewaretoken': [u'3eae081aeb54656ce0f4e599dbb4fcc0'], u'billing_detail_postcode': [u'46714'], u'card_name': [u'xxxx'], u'fr_shipping': [u'1'], u'shipping_detail_state': [u'Nevada'], u'billing_detail_state': [u'Nevada'], u'billing_detail_first_name': [u'xxx'], u'shipping_detail_street': [u'xxxx'], u'billing_detail_email': [u'[email protected]'], u'card_type': [u'Visa'], u'submit.x': [u'37'], u'submit.y': [u'18'], u'card_number': [u'xxxxx']}>"
Really quite confused on what might be causing the error. I am using the latest versions, I believe pulled from bitbucket.
As reported here:
https://groups.google.com/forum/#!topic/mezzanine-users/D5Wh5iTH2Aw
We recently added handling in the checkout steps to support leaving at a particular step, browsing the site further, then returning to the last step the user was at - I suspect this is the cause of one or more "handler" style functions not being called, since in the described case, the first step is skipped.
Perhaps we simply need to call the handler functions at each checkout step.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.