1. Sasha Vincic
  2. django-lfs

Commits

Sasha Vincic  committed fb100cc Merge

merge from tip

  • Participants
  • Parent commits b0155aa, 232ae5b
  • Branches default

Comments (0)

Files changed (39)

File .hgtags

View file
 953c1e3503b2e924bc24d5ded3d363d6e1bf3d9d 0.6.8
 baca3fb996542b6cf02c232b4e7bf1a576c7d6be 0.6.7
 76afc2b1bec9a0f1649fce4f60dfbc79fe1707f3 0.7.0b1
+2cf4031298a241b1e4522b837fa3b09c001bd4a1 0.6.9
+2cf4031298a241b1e4522b837fa3b09c001bd4a1 0.6.9
+0000000000000000000000000000000000000000 0.6.9
+0000000000000000000000000000000000000000 0.6.9
+d6a3c0f3de9d1f09891af9b1c2e817f3cc17a3a8 0.6.9
+>>>>>>> other

File HISTORY.txt

View file
 * Using Python's locale to display currencies
 * New contact form
 
+0.5.0 (2012-03-08)
+------------------
+
+* Security fix
+
+0.5.0 beta 8 (2011-06-25)
+-------------------------
+
+* Bugfix: pinned version of djangorecipe to 0.23.1
+* Enhancement: added active_name and active_price to variants management view; issue #51
+* Enhancement: cleaned up password reset templates
+
 0.5.0 beta 7 (2011-04-13)
 -------------------------
 

File README.txt

View file
 Changes
 =======
 
+0.7.0 beta 2
+------------
+
+* Security fix
+* Added manufacturer field to product management (Maciej Wiśniowski)
+* Bugfix: fixed pagination for product page; issue #152 (Maciej Wiśniowski)
+* Bugfix: fixed deleting of image for payment and shipping methods; issue #150
+* Bugfix: fixed markup; #issue #148
+* Bugfix: fixed updating of attachments; issue #147
+* Improved javascript: prevent FOUC for category-tabs and manage-tabs;
+
 0.7.0 beta 1
 ------------
 

File lfs/catalog/models.py

View file
         else:
             return self.sku
 
+    def get_manufacturer(self):
+        """Always return parent manufacturer for variants.
+        """
+        if self.is_variant():
+            return self.parent.manufacturer
+        else:
+            return self.manufacturer
+
     def has_related_products(self):
         """Returns True if the product has related products.
         """

File lfs/core/tests.py

View file
 
         self.assertEqual(currency(0.0, None, False), "USD 0.00")
         self.assertEqual(currency(1.0, None, False), "USD 1.00")
+
+
+class ManageURLsTestCase(TestCase):
+    def test_manage_urls_anonymous(self):
+        """Tests that all manage urls cannot accessed by anonymous user.
+        """
+        rf = RequestFactory()
+        request = rf.get("/")
+        request.user = AnonymousUser()
+
+        from lfs.manage.urls import urlpatterns
+        for url in urlpatterns:
+            result = url.callback(request)
+            self.failUnless(result["Location"].startswith("/login/?next=/"))

File lfs/manage/actions/views.py

View file
 
 
 # Actions
+@permission_required("core.manage_shop", login_url="/login/")
 @require_POST
-@permission_required("core.manage_shop", login_url="/login/")
 def save_action(request, id):
     """Saves the actions with passed id.
     """
     }))
 
 
+@permission_required("core.manage_shop", login_url="/login/")
 @require_POST
-@permission_required("core.manage_shop", login_url="/login/")
 def delete_action(request, id):
     """Deletes the action with passed id.
     """
     )
 
 
+@permission_required("core.manage_shop", login_url="/login/")
 @require_POST
-@permission_required("core.manage_shop", login_url="/login/")
 def sort_actions(request):
     """Sorts actions after drag 'n drop.
     """

File lfs/manage/customer_tax/views.py

View file
     }))
 
 
+@permission_required("core.manage_shop", login_url="/login/")
 @require_POST
-@permission_required("core.manage_shop", login_url="/login/")
 def delete_customer_tax(request, id):
     """Deletes customer tax with passed id.
     """

File lfs/manage/images/views.py

View file
 logger = logging.getLogger("default")
 
 # views
+@permission_required("core.manage_shop", login_url="/login/")
 def images(request, template_name="manage/images/images.html"):
     """
     Display images management.
     return HttpResponse(result)
 
 
+@permission_required("core.manage_shop", login_url="/login/")
 @require_POST
-@permission_required("core.manage_shop", login_url="/login/")
 def delete_images(request):
     """
     Deletes images which are passed via HTTP query.
     return HttpResponseRedirect(reverse("lfs_manage_global_images"))
 
 
+@permission_required("core.manage_shop", login_url="/login/")
 def add_images(request):
     """
     Adds a global images.

File lfs/manage/urls.py

View file
 from django.conf.urls.defaults import *
 from django.views.generic.simple import direct_to_template
 
-urlpatterns = patterns('django.views.generic.simple',
-    (r'^products-new', 'direct_to_template', {'template': 'manage/new/product.html'}),
-)
-
 # General
-urlpatterns += patterns('lfs.manage.views',
+urlpatterns = patterns('lfs.manage.views',
     url(r'^$', "dashboard", name="lfs_manage_dashboard"),
 )
 
     url(r'^edit-product-manufacturer/(?P<manufacturer_id>\d*)/(?P<product_id>\d*)$', "edit_product", name="lfs_manufacturer_edit_product"),
     url(r'^category-state-manufacturer/(?P<manufacturer_id>\d*)/(?P<category_id>\d*)$', "category_state", name="lfs_manufacturer_category_state"),
     url(r'^manufacturer-inline/(?P<manufacturer_id>\d*)/(?P<category_id>\d*)$', "manufacturer_inline", name="lfs_manufacturer_inline"),
+    url(r'^manufacturers-ajax/$', "manufacturers_ajax", name="lfs_manufacturers_ajax"),
 )
 
 # Marketing

File lfs/manage/views/carts.py

View file
     }))
 
 
+@permission_required("core.manage_shop", login_url="/login/")
 def carts_inline(request, template_name="manage/cart/carts_inline.html"):
     """Displays carts overview.
     """
     }))
 
 
+@permission_required("core.manage_shop", login_url="/login/")
 def cart_inline(request, cart_id, template_name="manage/cart/cart_inline.html"):
     """Displays cart with provided cart id.
     """
     }))
 
 
+@permission_required("core.manage_shop", login_url="/login/")
 def selectable_carts_inline(request, cart_id, template_name="manage/cart/selectable_carts_inline.html"):
     """Displays selectable carts section within cart view.
     """

File lfs/manage/views/categories/category.py

View file
     }))
 
 
+@permission_required("core.manage_shop", login_url="/login/")
 @require_POST
-@permission_required("core.manage_shop", login_url="/login/")
 def delete_category(request, id):
     """Deletes category with given id.
     """
     return HttpResponseRedirect(url)
 
 
+@permission_required("core.manage_shop", login_url="/login/")
 def sort_categories(request):
     """Sort categories
     """

File lfs/manage/views/customer.py

View file
     }))
 
 
+@permission_required("core.manage_shop", login_url="/login/")
 def customer_inline(request, customer_id, template_name="manage/customer/customer_inline.html"):
     """Displays customer with provided customer id.
     """
     }))
 
 
+@permission_required("core.manage_shop", login_url="/login/")
 def customers_inline(request, template_name="manage/customer/customers_inline.html"):
     """Displays carts overview.
     """
     }))
 
 
+@permission_required("core.manage_shop", login_url="/login/")
 def selectable_customers_inline(request, customer_id, template_name="manage/customer/selectable_customers_inline.html"):
     """Display selectable customers.
     """

File lfs/manage/views/delivery_times.py

View file
     }))
 
 
+@permission_required("core.manage_shop", login_url="/login/")
 @require_POST
-@permission_required("core.manage_shop", login_url="/login/")
 def delete_delivery_time(request, id):
     """Deletes the delivery time with passed id.
     """

File lfs/manage/views/discounts.py

View file
     )
 
 
+@permission_required("core.manage_shop", login_url="/login/")
 @require_POST
-@permission_required("core.manage_shop", login_url="/login/")
 def delete_discount(request, id):
     """Deletes discount with passed id.
     """

File lfs/manage/views/export.py

View file
         exclude = ("products", )
 
 
+@permission_required("core.manage_shop", login_url="/login/")
 def manage_export(request, export_id, template_name="manage/export/export.html"):
     """The main view to display exports.
     """
     }))
 
 
+@permission_required("core.manage_shop", login_url="/login/")
 def export_inline(request, export_id, category_id,
     template_name="manage/export/export_inline.html"):
     """Returns categories and products for given export id and category id.
         simplejson.dumps({ "html" : html }), content_type='application/json; charset=utf8')
 
 
+@permission_required("core.manage_shop", login_url="/login/")
 def add_export(request, template_name="manage/export/add_export.html"):
     """Form and logic to add a export.
     """
 
 
 # Actions
+@permission_required("core.manage_shop", login_url="/login/")
 def export_dispatcher(request):
     """Dispatches to the first export or to the add form.
     """
             reverse("lfs_export", kwargs={"export_id": export.id}))
 
 
+@permission_required("core.manage_shop", login_url="/login/")
 @require_POST
-@permission_required("core.manage_shop", login_url="/login/")
 def delete_export(request, export_id):
     """Deletes export with passed export id.
     """
     return HttpResponseRedirect(reverse("lfs_export_dispatcher"))
 
 
+@permission_required("core.manage_shop", login_url="/login/")
 def edit_category(request, export_id, category_id):
     """Adds/Removes products of given category to given export.
     """
     return HttpResponse("")
 
 
+@permission_required("core.manage_shop", login_url="/login/")
 def edit_product(request, export_id, product_id):
     """Adds/Removes given product to given export.
     """
     return HttpResponse("")
 
 
+@permission_required("core.manage_shop", login_url="/login/")
 def export(request, slug):
     """Exports the export with passed export id.
     """
     return getattr(module, export.script.method)(request, export)
 
 
+@permission_required("core.manage_shop", login_url="/login/")
 def category_state(request, export_id, category_id):
     """Sets the state (klass and checking) for given category for given
     export.
     )
 
 
+@permission_required("core.manage_shop", login_url="/login/")
 def update_category_variants_option(request, export_id, category_id):
     """Stores / deletes options for the variants handling of category with
     given id.
     return HttpResponse("")
 
 
+@permission_required("core.manage_shop", login_url="/login/")
 def update_data(request, export_id):
     """Updates data of export with given export id.
     """

File lfs/manage/views/lfs_portlets.py

View file
         except ContentType.DoesNotExist:
             pass
 
+
+@permission_required("core.manage_shop", login_url="/login/")
 @require_POST
-@permission_required("core.manage_shop", login_url="/login/")
 def delete_portlet(request, portletassignment_id):
     """Deletes a portlet for given portlet assignment.
     """
         }))
 
 
+@permission_required("core.manage_shop", login_url="/login/")
 def move_portlet(request, portletassignment_id):
     """
     Moves a portlet up/down within a slot.

File lfs/manage/views/manufacturer.py

View file
 from django.utils import simplejson
 from django.utils.translation import ugettext_lazy as _
 from django.views.decorators.http import require_POST
+from django.views.decorators.cache import never_cache
 
 # lfs imports
 import lfs.core.utils
 from lfs.catalog.models import Product
 from lfs.core.utils import LazyEncoder
 from lfs.manufacturer.models import Manufacturer
-from lfs.manufacturer.models import Manufacturer
 
 
 class ManufacturerDataForm(ModelForm):
         model = Manufacturer
 
 
+@permission_required("core.manage_shop", login_url="/login/")
 def manage_manufacturer(request, manufacturer_id, template_name="manage/manufacturer/manufacturer.html"):
     """The main view to display manufacturers.
     """
     }))
 
 
+@permission_required("core.manage_shop", login_url="/login/")
 def manufacturer_inline(request, manufacturer_id, category_id,
     template_name="manage/manufacturer/manufacturer_inline.html"):
     """Returns categories and products for given manufacturer id and category id.
         simplejson.dumps({ "html" : html }), content_type='application/json; charset=utf8')
 
 
+@permission_required("core.manage_shop", login_url="/login/")
 def add_manufacturer(request, template_name="manage/manufacturer/add_manufacturer.html"):
     """Form and logic to add a manufacturer.
     """
 
 
 # Actions
+@permission_required("core.manage_shop", login_url="/login/")
 def manufacturer_dispatcher(request):
     """Dispatches to the first manufacturer or to the add form.
     """
             reverse("lfs_manufacturer", kwargs={"manufacturer_id": manufacturer.id}))
 
 
+@permission_required("core.manage_shop", login_url="/login/")
 @require_POST
-@permission_required("core.manage_shop", login_url="/login/")
 def delete_manufacturer(request, manufacturer_id):
     """Deletes Manufacturer with passed manufacturer id.
     """
     return HttpResponseRedirect(reverse("lfs_manufacturer_dispatcher"))
 
 
+@permission_required("core.manage_shop", login_url="/login/")
 def edit_category(request, manufacturer_id, category_id):
     """Adds/Removes products of given category to given manufacturer.
     """
     return HttpResponse("")
 
 
+@permission_required("core.manage_shop", login_url="/login/")
 def edit_product(request, manufacturer_id, product_id):
     """Adds/Removes given product to given manufacturer.
     """
     return HttpResponse("")
 
 
+@permission_required("core.manage_shop", login_url="/login/")
 def category_state(request, manufacturer_id, category_id):
     """Sets the state (klass and checking) for given category for given
     manufacturer.
     )
 
 
+@permission_required("core.manage_shop", login_url="/login/")
 def update_data(request, manufacturer_id):
     """Updates data of manufacturer with given manufacturer id.
     """
         klass = ""
 
     return (checked, klass)
+
+
+@never_cache
+@permission_required("core.manage_shop", login_url="/login/")
+def manufacturers_ajax(request):
+    """ Returns list of manufacturers for autocomplete
+    """
+    term = request.GET.get('term', '')
+    manufacturers = Manufacturer.objects.filter(name__istartswith=term)[:10]
+
+    out = []
+    for man in manufacturers:
+        out.append({'label': man.name,
+                    'value': man.pk})
+
+    result = simplejson.dumps(out, cls=LazyEncoder)
+    return HttpResponse(result)

File lfs/manage/views/orders.py

View file
 
 
 # Parts
+@permission_required("core.manage_shop", login_url="/login/")
 def orders_inline(request, template_name="manage/order/orders_inline.html"):
     """Displays the orders. This is factored out in order to reload it via
     ajax request when the filter is changed..
     return HttpResponse(result, content_type='application/json; charset=utf8')
 
 
+@permission_required("core.manage_shop", login_url="/login/")
 @require_POST
-@permission_required("core.manage_shop", login_url="/login/")
 def delete_order(request, order_id):
     """Deletes order with provided order id.
     """
     )
 
 
+@permission_required("core.manage_shop", login_url="/login/")
 @require_POST
-@permission_required("core.manage_shop", login_url="/login/")
 def change_order_state(request):
     """Changes the state of an order, given by request post variables.
     """

File lfs/manage/views/page.py

View file
     }))
 
 
+@permission_required("core.manage_shop", login_url="/login/")
 @require_POST
-@permission_required("core.manage_shop", login_url="/login/")
 def delete_page(request, id):
     """Deletes the page with passed id.
     """
     )
 
 
+@permission_required("core.manage_shop", login_url="/login/")
 @require_POST
-@permission_required("core.manage_shop", login_url="/login/")
 def sort_pages(request):
     """Sorts pages after drag 'n drop.
     """

File lfs/manage/views/payment.py

View file
 
     if payment_form.is_valid():
         payment_form.save()
+        if request.POST.get("delete_image"):
+            payment_method.image.delete()
 
     return lfs.core.utils.set_message_cookie(
         url=reverse("lfs_manage_payment_method", kwargs={"payment_method_id": payment_method.id}),
     )
 
 
+@permission_required("core.manage_shop", login_url="/login/")
 @require_POST
-@permission_required("core.manage_shop", login_url="/login/")
 def delete_payment_method(request, payment_method_id):
     """Deletes payment method with passed payment id.
 
     )
 
 
+@permission_required("core.manage_shop", login_url="/login/")
 @require_POST
-@permission_required("core.manage_shop", login_url="/login/")
 def sort_payment_methods(request):
     """Sorts payment methods after drag 'n drop.
     """

File lfs/manage/views/product/attachments.py

View file
                     pass
     elif action == "update":
         message = _(u"Attachment has been updated.")
-        for attachment in ProductAttachment.objects.all():
+        for attachment in product.attachments.all():
             attachment.title = request.POST.get("title-%s" % attachment.id)
             attachment.position = request.POST.get("position-%s" % attachment.id)
             attachment.description = request.POST.get("description-%s" % attachment.id)

File lfs/manage/views/product/product.py

View file
 from django.utils import simplejson
 from django.utils.translation import ugettext_lazy as _
 from django.views.decorators.http import require_POST
+from django.forms.widgets import HiddenInput
+from django.conf import settings
 
 # lfs imports
 import lfs.core.utils
 from lfs.manage.views.product.attachments import manage_attachments
 from lfs.manage.views.lfs_portlets import portlets_inline
 from lfs.manage.utils import get_current_page
+from lfs.manufacturer.models import Manufacturer
 from lfs.utils.widgets import SelectImage
 
 
         super(ProductDataForm, self).__init__(*args, **kwargs)
         self.fields["template"].widget = SelectImage(choices=PRODUCT_TEMPLATES)
         self.fields["active_base_price"].widget = CheckboxInput()
+        man_count = Manufacturer.objects.count()
+        if man_count > getattr(settings, 'LFS_SELECT_LIMIT', 20):
+            self.fields["manufacturer"].widget = HiddenInput()
 
     class Meta:
         model = Product
-        fields = ("active", "name", "slug", "sku", "sku_manufacturer", "price", "tax", "price_calculator",
+        fields = ("active", "name", "slug", "manufacturer", "sku", "sku_manufacturer", "price", "tax", "price_calculator",
             "short_description", "description", "for_sale", "for_sale_price", "static_block", "template",
             "active_price_calculation", "price_calculation", "price_unit", "unit", "type_of_quantity_field",
             "active_base_price", "base_price_unit", "base_price_amount")
     """
     class Meta:
         model = Product
-        fields = ("active", "active_name", "name", "slug", "active_sku", "sku", "sku_manufacturer",
+        fields = ("active", "active_name", "name", "slug", "manufacturer", "active_sku", "sku", "sku_manufacturer",
             "active_price", "price", "price_calculator", "active_short_description", "short_description", "active_description",
             "description", "for_sale", "for_sale_price", "active_for_sale", "active_for_sale_price",
             "active_related_products", "active_static_block", "static_block", "template",
     """
     Displays the whole manage/edit form for the product with the passed id.
     """
-    AMOUNT = 20
     product = lfs_get_object_or_404(Product, pk=product_id)
     products = _get_filtered_products_for_product_view(request)
-    paginator = Paginator(products, AMOUNT)
-
+    paginator = Paginator(products, 25)
     temp = product.parent if product.is_variant() else product
-    page = get_current_page(request, products, temp, AMOUNT)
+    page = get_current_page(request, products, temp, 25)
 
     try:
         page = paginator.page(page)
     )
 
 
+@permission_required("core.manage_shop", login_url="/login/")
 @require_POST
-@permission_required("core.manage_shop", login_url="/login/")
 def delete_product(request, product_id):
     """Deletes product with passed id.
     """
     return HttpResponseRedirect(url)
 
 
+@permission_required("core.manage_shop", login_url="/login/")
 @require_POST
-@permission_required("core.manage_shop", login_url="/login/")
 def edit_product_data(request, product_id, template_name="manage/product/data.html"):
     """Edits the product with given.
     """
     product = lfs_get_object_or_404(Product, pk=product_id)
     products = _get_filtered_products_for_product_view(request)
-    paginator = Paginator(products, 20)
+    paginator = Paginator(products, 25)
     page = paginator.page(request.REQUEST.get("page", 1))
 
     # Transform empty field / "on" from checkbox to integer
         del request.session["product_filters"]
 
     products = _get_filtered_products(request)
-    paginator = Paginator(products, 20)
+    paginator = Paginator(products, 25)
     page = paginator.page(request.REQUEST.get("page", 1))
 
     product_id = request.REQUEST.get("product-id", 0)
 
 
 
+@permission_required("core.manage_shop", login_url="/login/")
 @require_POST
-@permission_required("core.manage_shop", login_url="/login/")
 def save_products(request):
     """
     Saves products with passed ids (by request body).
     """
     products = _get_filtered_products(request)
-    paginator = Paginator(products, 20)
+    paginator = Paginator(products, 25)
     page = paginator.page(request.REQUEST.get("page", 1))
 
     if request.POST.get("action") == "delete":
     request.session["product_filters"] = product_filters
 
     products = _get_filtered_products_for_product_view(request)
-    paginator = Paginator(products, 20)
+    paginator = Paginator(products, 25)
     page = paginator.page(request.REQUEST.get("page", 1))
 
     product_id = request.REQUEST.get("product-id", 0)

File lfs/manage/views/product/properties.py

View file
     }))
 
 
+@permission_required("core.manage_shop", login_url="/login/")
 @require_POST
-@permission_required("core.manage_shop", login_url="/login/")
 def update_property_groups(request, product_id):
     """Updates property groups for the product with passed id.
     """
     return HttpResponseRedirect(url)
 
 
+@permission_required("core.manage_shop", login_url="/login/")
 @require_POST
-@permission_required("core.manage_shop", login_url="/login/")
 def update_properties(request, product_id):
     """Updates properties for product with passed id.
     """

File lfs/manage/views/properties.py

View file
       }))
 
 
+@permission_required("core.manage_shop", login_url="/login/")
 @require_POST
-@permission_required("core.manage_shop", login_url="/login/")
 def update_property_type(request, id):
     """Updates the type of the property.
 
     }))
 
 
+@permission_required("core.manage_shop", login_url="/login/")
 @require_POST
 def save_select_field(request, property_id):
     """Saves the data of a property select field.
     }))
 
 
+@permission_required("core.manage_shop", login_url="/login/")
 @require_POST
-@permission_required("core.manage_shop", login_url="/login/")
 def save_number_field_validators(request, property_id):
     """Saves the validators for the property with passed property_id.
     """
     }))
 
 
+@permission_required("core.manage_shop", login_url="/login/")
 @require_POST
-@permission_required("core.manage_shop", login_url="/login/")
 def save_step_range(request, property_id):
     """Save the steps of the property with given id.
     """
     return HttpResponse(result, content_type='application/json; charset=utf8')
 
 
+@permission_required("core.manage_shop", login_url="/login/")
 @require_POST
-@permission_required("core.manage_shop", login_url="/login/")
 def save_step_type(request, property_id):
     """Save the step type of the property with given id.
     """
     return HttpResponse(result, content_type='application/json; charset=utf8')
 
 
+@permission_required("core.manage_shop", login_url="/login/")
 @require_POST
-@permission_required("core.manage_shop", login_url="/login/")
 def add_step(request, property_id):
     """Adds a step to property with passed property id resp. updates steps of
     property with passed property id dependent on the given action parameter.
     }))
 
 
+@permission_required("core.manage_shop", login_url="/login/")
 @require_POST
-@permission_required("core.manage_shop", login_url="/login/")
 def delete_property(request, id):
     """Deletes the property with given id.
     """
     return HttpResponseRedirect(url)
 
 
+@permission_required("core.manage_shop", login_url="/login/")
 @require_POST
-@permission_required("core.manage_shop", login_url="/login/")
 def add_option(request, property_id):
     """Adds option to property with passed property id.
     """

File lfs/manage/views/property_groups/property_groups.py

View file
     }))
 
 
+@permission_required("core.manage_shop", login_url="/login/")
 @require_POST
-@permission_required("core.manage_shop", login_url="/login/")
 def delete_property_group(request, id):
     """Deletes the property group with passed id.
     """

File lfs/manage/views/review.py

View file
     return HttpResponse(result, content_type='application/json; charset=utf8')
 
 
+@permission_required("core.manage_shop", login_url="/login/")
 @require_POST
-@permission_required("core.manage_shop", login_url="/login/")
 def delete_review(request, review_id):
     """Deletes review with passed review id.
     """

File lfs/manage/views/shipping.py

View file
 
     if shipping_form.is_valid():
         shipping_form.save()
+        if request.POST.get("delete_image"):
+            shipping_method.image.delete()
 
     return lfs.core.utils.set_message_cookie(
         url=reverse("lfs_manage_shipping_method", kwargs={"shipping_method_id": shipping_method.id}),
     )
 
 
+@permission_required("core.manage_shop", login_url="/login/")
 @require_POST
-@permission_required("core.manage_shop", login_url="/login/")
 def delete_shipping_method(request, shipping_method_id):
     """Deletes shipping method with passed shipping id.
 
     )
 
 
+@permission_required("core.manage_shop", login_url="/login/")
 @require_POST
-@permission_required("core.manage_shop", login_url="/login/")
 def sort_shipping_methods(request):
     """Sorts shipping methods after drag 'n drop.
     """

File lfs/manage/views/shop.py

View file
 
 
 # Actions
+@permission_required("core.manage_shop", login_url="/login/")
 @require_POST
-@permission_required("core.manage_shop", login_url="/login/")
 def save_data_tab(request):
     """Saves the data tab of the default shop.
     """
     return HttpResponse(result, content_type='application/json; charset=utf8')
 
 
+@permission_required("core.manage_shop", login_url="/login/")
 @require_POST
-@permission_required("core.manage_shop", login_url="/login/")
 def save_default_values_tab(request):
     """Saves the default value part
     """
     return HttpResponse(result, content_type='application/json; charset=utf8')
 
 
+@permission_required("core.manage_shop", login_url="/login/")
 @require_POST
-@permission_required("core.manage_shop", login_url="/login/")
 def save_seo_tab(request):
     """Saves the seo tab of the default shop.
     """
     return HttpResponse(result, content_type='application/json; charset=utf8')
 
 
+@permission_required("core.manage_shop", login_url="/login/")
 @require_POST
-@permission_required("core.manage_shop", login_url="/login/")
 def save_order_numbers_tab(request):
     """Saves the order number tab of the default shop.
     """

File lfs/manage/views/static_blocks.py

View file
     }))
 
 
+@permission_required("core.manage_shop", login_url="/login/")
 def update_files(request, id):
     """
     """
     return HttpResponse(result, content_type='application/json; charset=utf8')
 
 
+@permission_required("core.manage_shop", login_url="/login/")
 def reload_files(request, id):
     """
     """
     return HttpResponse(result, content_type='application/json; charset=utf8')
 
 
+@permission_required("core.manage_shop", login_url="/login/")
 def add_files(request, id):
     """Adds files to static block with passed id.
     """
     }))
 
 
+@permission_required("core.manage_shop", login_url="/login/")
 @require_POST
-@permission_required("core.manage_shop", login_url="/login/")
 def sort_static_blocks(request):
     """Sorts static blocks after drag 'n drop.
     """
         return HttpResponse(result)
 
 
+@permission_required("core.manage_shop", login_url="/login/")
 @require_POST
-@permission_required("core.manage_shop", login_url="/login/")
 def delete_static_block(request, id):
     """Deletes static block with passed id.
     """

File lfs/manage/views/tax.py

View file
     }))
 
 
+@permission_required("core.manage_shop", login_url="/login/")
 @require_POST
-@permission_required("core.manage_shop", login_url="/login/")
 def delete_tax(request, id):
     """Deletes tax with passed id.
     """

File lfs/manage/views/voucher.py

View file
 
 
 # Parts
+@permission_required("core.manage_shop", login_url="/login/")
 def voucher_group(request, id, template_name="manage/voucher/voucher_group.html"):
     """Main view to display a voucher group.
     """
         simplejson.dumps({"html": html}, cls=LazyEncoder), content_type='application/json; charset=utf8')
 
 
+@permission_required("core.manage_shop", login_url="/login/")
 def manage_vouchers(request):
     """Redirects to the first voucher group or to the add voucher form.
     """
     return HttpResponseRedirect(url)
 
 
+@permission_required("core.manage_shop", login_url="/login/")
 def add_vouchers(request, group_id):
     """
     """
         msg)
 
 
+@permission_required("core.manage_shop", login_url="/login/")
 @require_POST
-@permission_required("core.manage_shop", login_url="/login/")
 def delete_vouchers(request, group_id):
     """Deletes checked vouchers.
     """
         _(u"Vouchers have been deleted."))
 
 
+@permission_required("core.manage_shop", login_url="/login/")
 def add_voucher_group(request, template_name="manage/voucher/add_voucher_group.html"):
     """Adds a voucher group
     """
     }))
 
 
+@permission_required("core.manage_shop", login_url="/login/")
 def save_voucher_group_data(request, id):
     """Saves the data of the voucher group with passed id.
     """
         _(u"Voucher data has been saved."))
 
 
+@permission_required("core.manage_shop", login_url="/login/")
 @require_POST
-@permission_required("core.manage_shop", login_url="/login/")
 def delete_voucher_group(request, id):
     """Deletes voucher group with given id and all assigned vouchers.
     """
         )
 
 
+@permission_required("core.manage_shop", login_url="/login/")
 def save_voucher_options(request):
     """Saves voucher options.
     """

File lfs/static/css/lfs.manage.css

View file
 /* input fields */
 #id_name, #id_slug, #id_sku, #id_shop_owner, #id_from_email, #id_title, #id_redirect_to, #id_sku_manufacturer, #redirect_to, #id_position, #id_unit,
 #id_priority, #id_price, #id_for_sale_price, #id_tax, #id_module, #id_link, #id_parent, #id_static_block, #id_price_unit, #id_template, #id_meta_title,
-#id_type, #id_step_type, #id_delivery_time, #id_type_of_quantity_field, #id_price_calculator, #id_base_price_unit, #id_base_price_amount, #id_active_base_price {
+#id_type, #id_step_type, #id_delivery_time, #id_type_of_quantity_field, #id_price_calculator, #id_base_price_unit, #id_base_price_amount, #id_active_base_price,
+#id_manufacturer_autocomplete, #id_manufacturer {
     width: 200px;
 }
 

File lfs/static/js/lfs.manage.js

View file
 			// ReferenceError due to undefined tinymce
 	    }
         show_ajax_loading();
+
+        // trigger form-save-start event when form is about to be submitted
+        var form = $(this).closest("form");
+        var form_id = form.get(0).id;
+        var event = jQuery.Event("form-save-start");
+        event.form_id = form_id;
+        $('body').trigger(event);
+
         var action = $(this).attr("name")
-        $(this).parents("form:first").ajaxSubmit({
+        form.ajaxSubmit({
             data : {"action" : action},
             success : function(data) {
                 for (var html in data["html"]) {
                 }
                 hide_ajax_loading();
                 update_editor();
+
+                // trigger form-save-end event when new HTML has already been injected into page
+                var event = jQuery.Event("form-save-end");
+                event.form_id = form_id;
+                $('body').trigger(event);
             }
         })
         return false;
         knot.parent().find(".category-state").html("");
     };
 
-    $(function() {
-        $(".category-ajax-link").live("click", function() {
-            var url = $(this).attr("href");
+    $(".category-ajax-link").live("click", function() {
+        var url = $(this).attr("href");
 
-            // Loads children of clicked category.
-            if ($(this).hasClass("collapsed")) {
-                $.post(url, function(data) {
-                    for (var html in data["html"])
-                        $(data["html"][html][0]).html(data["html"][html][1]);
-                })
-                $(this).removeClass("collapsed");
-                $(this).addClass("expanded");
-            }
-            // Removes children of clicked category.
-            else {
-                $(this).siblings("div").html("")
-                $(this).removeClass("expanded");
-                $(this).addClass("collapsed");
-            }
-            return false;
-        });
+        // Loads children of clicked category.
+        if ($(this).hasClass("collapsed")) {
+            $.post(url, function(data) {
+                data = $.parseJSON(data);
+                for (var html in data["html"])
+                    $(data["html"][html][0]).html(data["html"][html][1]);
+            })
+            $(this).removeClass("collapsed");
+            $(this).addClass("expanded");
+        }
+        // Removes children of clicked category.
+        else {
+            $(this).siblings("div").html("")
+            $(this).removeClass("expanded");
+            $(this).addClass("collapsed");
+        }
+        return false;
+    });
 
-        $(".export-category-input").live("click", function() {
+    $(".export-category-input").live("click", function() {
 
-            // select / deselect all child nodes
-            var input = $(this);
-            var parent_checked = this.checked;
-            $(this).parent().find("input").each(function() { this.checked = parent_checked; })
+        // select / deselect all child nodes
+        var input = $(this);
+        var parent_checked = this.checked;
+        $(this).parent().find("input").each(function() { this.checked = parent_checked; })
 
-            // Updates child and parent categories of clicked category
-            var url = $(this).attr("data");
-            if (parent_checked == true) {
-                $.post(url, {"action" : "add"}, function(data) {
-                    update_sub_categories(input);
-                    update_parent_categories(input);
-                });
-            }
-            else {
-                $.post(url, {"action" : "remove"}, function(data) {
-                    update_sub_categories(input);
-                    update_parent_categories(input);
-                });
-            }
-        });
+        // Updates child and parent categories of clicked category
+        var url = $(this).attr("data");
+        if (parent_checked == true) {
+            $.post(url, {"action" : "add"}, function(data) {
+                update_sub_categories(input);
+                update_parent_categories(input);
+            });
+        }
+        else {
+            $.post(url, {"action" : "remove"}, function(data) {
+                update_sub_categories(input);
+                update_parent_categories(input);
+            });
+        }
+    });
 
-        $(".export-product-input").live("click", function() {
-            // Add / Remove product
-            var input = $(this);
-            var url = $(this).attr("data");
-            var checked = this.checked;
+    $(".export-product-input").live("click", function() {
+        // Add / Remove product
+        var input = $(this);
+        var url = $(this).attr("data");
+        var checked = this.checked;
 
-            // Updates parent catgories of clicked product
-            if (checked == true) {
-                $.post(url, {"action" : "add"}, function(data) { update_parent_categories(input) } );
-            }
-            else {
-                $.post(url, {"action" : "remove"}, function(data) { update_parent_categories(input) });
-            }
-        });
+        // Updates parent catgories of clicked product
+        if (checked == true) {
+            $.post(url, {"action" : "add"}, function(data) { update_parent_categories(input) } );
+        }
+        else {
+            $.post(url, {"action" : "remove"}, function(data) { update_parent_categories(input) });
+        }
     });
 
     $(".category-variants-options").live("change", function() {

File lfs/static/js/lfs.manage.product.js

View file
+/* Handle autocomplete on manufacturer field at product management page
+ * Uses jquery UI autocomplete implementation
+ */
+$(function() {
+    var MANUFACTURER_AUTOCOMPLETE_SETTINGS = {
+         source: MANUFACTURERS_AJAX_URL,
+         select: function(event, ui){
+             $('#id_manufacturer').val(ui.item.value);
+             $('#id_manufacturer_autocomplete').val(ui.item.label);
+             return false;
+         },
+         focus: function(event, ui){
+             $('#id_manufacturer').val(ui.item.value);
+             $('#id_manufacturer_autocomplete').val(ui.item.label);
+             return false;
+         },
+         change: function(event, ui){
+             if (ui.item === null){
+                 // only accept items selected from the list
+                 $('#id_manufacturer').val('');
+                 $('#id_manufacturer_autocomplete').val('');
+             }
+             return false;
+         },
+         minLength: 1
+    };
+
+    $('#id_manufacturer_autocomplete').autocomplete(MANUFACTURER_AUTOCOMPLETE_SETTINGS);
+    $('body').bind('form-save-start', function(evt){
+        if (evt.form_id == 'product-data-form'){
+            // ensure that manufacturer_id is cleared if autocomplete field is empty
+            if ($('#id_manufacturer_autocomplete').val() === ''){
+                $('#id_manufacturer').val('');
+            }
+        }
+    });
+
+    // when form is reloaded we have to reattach autocomplete
+    $('body').bind('form-save-end', function(evt){
+        if (evt.form_id == 'product-data-form'){
+            $('#id_manufacturer_autocomplete').autocomplete(MANUFACTURER_AUTOCOMPLETE_SETTINGS);
+        }
+    });
+})

File lfs/templates/manage/order/order_inline.html

View file
                     {{ current_order.shipping_line2 }}
                 </div>
             {% endif %}
-                <div>
-                {{ current_order.shipping_city }}
+            <div>
+                {{ current_order.shipping_code }} {{ current_order.shipping_city }}
             </div>
             <div>
                 {{ current_order.shipping_state }}
             </div>
             <div>
-                {{ current_order.shipping_code }}
-            </div>
-            <div>
                 {{ current_order.shipping_country }}
             </div>
             <div>
                 </div>
             {% endif %}
             <div>
-                {{ current_order.invoice_city }}
+                {{ current_order.invoice_code }} {{ current_order.invoice_city }}
             </div>
             <div>
                 {{ current_order.invoice_state }}
             </div>
             <div>
-                {{ current_order.invoice_code }}
-            </div>
-            <div>
                 {{ current_order.invoice_country }}
             </div>
             <div>

File lfs/templates/manage/product/data.html

View file
                     </div>
                 {% endif %}
             </div>
+
+            <div class="field">
+                <div class="label">
+                    {{ form.manufacturer.label_tag }}:
+                </div>
+
+                {% if form.manufacturer.errors %}
+                    <div class="error">
+                        {{ form.manufacturer }}
+                        {{ form.manufacturer.errors }}
+                    </div>
+                {% else %}
+                    <div>
+                        {% if product.is_variant %}
+                            {{ product.get_manufacturer|default_if_none:"-" }}
+                        {% else %}
+                            {{ form.manufacturer }}
+                            {% if form.manufacturer.is_hidden %}
+                                <input type="text" id="id_manufacturer_autocomplete" value="{{ form.instance.manufacturer.name }}" />
+                            {% endif %}
+                        {% endif %}
+                    </div>
+                {% endif %}
+            </div>
+
             <div class="field">
                 <div class="label">
                     {{ form.sku_manufacturer.label_tag }}:

File lfs/templates/manage/product/product.html

View file
 {% block help_link %}user/management/catalog/products.html{% endblock %}
 {% block section %}manage-product{% endblock %}
 
+{% block javascript %}
+    <script type="text/javascript" src="{{ STATIC_URL }}js/lfs.manage.product.js"></script>
+    <script type="text/javascript">
+        var MANUFACTURERS_AJAX_URL = '{% url lfs_manufacturers_ajax %}';
+    </script>
+{% endblock %}
+
 {% block left_slot %}
     <form action="{% url lfs_set_product_name_filter %}"
           method="post">

File lfs/templates/manage/voucher/options.html

View file
       method="post">
 
     {% include "manage/lfs_form.html" %}
-    
+
     <div class="buttons">
         <input class="padding-top ajax-save-button button"
                type="submit"
-               value='{% trans "Save options" %}'
+               value='{% trans "Save options" %}' />
     </div>
 
 </form>

File setup.py

File contents unchanged.