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

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

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 DetailView, UpdateView

from shuup.admin.form_modifier import ModifiableFormMixin, ModifiableViewMixin
from shuup.admin.toolbar import PostActionButton, Toolbar
from shuup.admin.utils.forms import add_form_errors_as_messages
from shuup.admin.utils.urls import get_model_url
from shuup.core.excs import (
    NoProductsToShipException, NoShippingAddressException
)
from shuup.core.models import Order, Product, Shipment, Supplier
from shuup.utils.excs import Problem


[docs]class ShipmentForm(ModifiableFormMixin, forms.Form): form_modifier_provide_key = "admin_extend_create_shipment_form" description = forms.CharField(required=False) tracking_code = forms.CharField(required=False)
[docs]class OrderCreateShipmentView(ModifiableViewMixin, UpdateView): model = Order template_name = "shuup/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
[docs] def get_form(self): default_field_keys = set() form = super(OrderCreateShipmentView, self).get_form() 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) 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 create_shipment(self, order, product_quantities, shipment): """ This function exists so subclasses can implement custom logic without overriding the entire form_valid method :param order: Order to create the shipment for :type order: shuup.core.models.Order :param product_quantities: a dict mapping Product instances to quantities to ship :type product_quantities: dict[shuup.shop.models.Product, decimal.Decimal] :param shipment: unsaved Shipment for ShipmentProduct's. :type shipment: shuup.core.models.Shipment :return: Saved, complete Shipment object :rtype: shuup.core.models.Shipment """ return order.create_shipment( product_quantities=product_quantities, shipment=shipment )
[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 if value else False) ) 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"], tracking_code=form.cleaned_data.get("tracking_code"), description=form.cleaned_data.get("description"),) has_extension_errors = self.form_valid_hook(form, unsaved_shipment) if has_extension_errors: return self.form_invalid(form) try: shipment = self.create_shipment( order=order, product_quantities=products_to_quantities, shipment=unsaved_shipment ) except Problem as problem: messages.error(self.request, problem) return self.form_invalid(form) except NoProductsToShipException: messages.error(self.request, _("No products to ship.")) return self.form_invalid(form) except NoShippingAddressException: messages.error(self.request, _("Shipping address is not set.")) else: messages.success(self.request, _("Shipment %s created.") % shipment.id) return HttpResponseRedirect(get_model_url(order))
[docs]class ShipmentDeleteView(DetailView): model = Shipment context_object_name = "shipment"
[docs] def get(self, request, *args, **kwargs): shipment = self.get_object() return HttpResponseRedirect(get_model_url(shipment.order))
[docs] def post(self, request, *args, **kwargs): shipment = self.get_object() shipment.soft_delete() messages.success(request, _("Shipment %s has been deleted.") % shipment.pk) return HttpResponseRedirect(get_model_url(shipment.order))