Source code for shoop.admin.modules.orders.views.shipment

# -*- coding: utf-8 -*-
# This file is part of Shoop.
#
# Copyright (c) 2012-2016, Shoop Ltd. All rights reserved.
#
# This source code is licensed under the AGPLv3 license found in the
# LICENSE file in the root directory of this source tree.
from __future__ import unicode_literals

import abc

import six
from django import forms
from django.contrib import messages
from django.http.response import HttpResponseRedirect
from django.utils.translation import ugettext as _
from django.views.generic import UpdateView

from shoop.admin.toolbar import PostActionButton, Toolbar
from shoop.admin.utils.forms import add_form_errors_as_messages
from shoop.admin.utils.urls import get_model_url
from shoop.apps.provides import get_provide_objects
from shoop.core.excs import NoProductsToShipException
from shoop.core.models import Order, Product, Shipment, Supplier

FORM_MODIFIER_PROVIDER_KEY = "admin_extend_create_shipment_form"


[docs]class ShipmentFormModifier(six.with_metaclass(abc.ABCMeta)):
[docs] def get_extra_fields(self, order): """ Extra fields for shipment creation view. :param order: Order linked to form :type order: shoop.core.models.Order :return: List of extra fields that should be added to form. Tuple should contain field name and Django form field. :rtype: list[(str,django.forms.Field)] """ pass
[docs] def clean_hook(self, form): """ Extra clean for shipment creation form. This hook will be called in `~Django.forms.Form.clean` method of the form, after calling parent clean. Implementor of this hook may call `~Django.forms.Form.add_error` to add errors to form or modify the ``form.cleaned_data`` dictionary. :param form: Form that is currently cleaned :type form: ShipmentForm :rtype: None """ pass
[docs] def form_valid_hook(self, form, shipment): """ Extra form valid handler for shipment creation view. This is called from ``OrderCreateShipmentView`` just before the ``Order.create_shipment`` :param form: Form that is currently handled :type form: ShipmentForm :param shipment: Unsaved shipment :type shipment: shoop.core.models.Shipment :rtype: None """ pass
[docs]class ShipmentForm(forms.Form):
[docs] def clean(self): cleaned_data = super(ShipmentForm, self).clean() for extend_class in get_provide_objects(FORM_MODIFIER_PROVIDER_KEY): extend_class().clean_hook(self) return cleaned_data
[docs]class OrderCreateShipmentView(UpdateView): model = Order template_name = "shoop/admin/orders/create_shipment.jinja" context_object_name = "order" form_class = ShipmentForm # Augmented manually
[docs] def get_context_data(self, **kwargs): context = super(OrderCreateShipmentView, self).get_context_data(**kwargs) context["title"] = _("Create Shipment -- %s") % context["order"] context["toolbar"] = Toolbar([ PostActionButton( icon="fa fa-check-circle", form_id="create_shipment", text=_("Create Shipment"), extra_css_class="btn-success", ), ]) return context
[docs] def get_form_kwargs(self): kwargs = super(OrderCreateShipmentView, self).get_form_kwargs() kwargs.pop("instance") return kwargs
def get_form(self, form_class): default_field_keys = set() form = super(OrderCreateShipmentView, self).get_form(form_class) order = self.object form.fields["supplier"] = forms.ModelChoiceField( queryset=Supplier.objects.all(), initial=Supplier.objects.first(), label=_("Supplier") ) default_field_keys.add("supplier") form.product_summary = order.get_product_summary() form.product_names = dict( (product_id, text) for (product_id, text) in order.lines.exclude(product=None).values_list("product_id", "text") ) for product_id, info in sorted(six.iteritems(form.product_summary)): product_name = form.product_names.get(product_id, "Product %s" % product_id) unshipped_count = info["unshipped"] attrs = {"data-max": unshipped_count, "class": "form-control text-right", } if unshipped_count == 0: attrs["disabled"] = "disabled" field = forms.DecimalField( required=bool(unshipped_count != 0), min_value=0, max_value=unshipped_count, initial=0, label=product_name, widget=forms.TextInput(attrs=attrs) ) field_key = "q_%s" % product_id form.fields[field_key] = field default_field_keys.add(field_key) for extend_class in get_provide_objects(FORM_MODIFIER_PROVIDER_KEY): for field_key, field in extend_class().get_extra_fields(order) or []: form.fields[field_key] = field form.default_field_keys = default_field_keys return form
[docs] def form_invalid(self, form): add_form_errors_as_messages(self.request, form) return super(OrderCreateShipmentView, self).form_invalid(form)
[docs] def form_valid(self, form): product_ids_to_quantities = dict( (int(key.replace("q_", "")), value) for (key, value) in six.iteritems(form.cleaned_data) if key.startswith("q_") and value > 0 ) order = self.object product_map = Product.objects.in_bulk(set(product_ids_to_quantities.keys())) products_to_quantities = dict( (product_map[product_id], quantity) for (product_id, quantity) in six.iteritems(product_ids_to_quantities) ) unsaved_shipment = Shipment(order=order, supplier=form.cleaned_data["supplier"]) for extend_class in get_provide_objects(FORM_MODIFIER_PROVIDER_KEY): extend_class().form_valid_hook(form, unsaved_shipment) try: shipment = order.create_shipment( product_quantities=products_to_quantities, shipment=unsaved_shipment ) except NoProductsToShipException: messages.error(self.request, _("No products to ship.")) return self.form_invalid(form) else: messages.success(self.request, _("Shipment %s created.") % shipment.id) return HttpResponseRedirect(get_model_url(order))