# -*- coding: utf-8 -*-
# This file is part of Shuup.
#
# Copyright (c) 2012-2021, Shuup Commerce Inc. 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.template.loader import render_to_string
from django.utils.translation import gettext_lazy as _
from django.views.generic import DetailView, UpdateView
from shuup.admin.form_modifier import ModifiableFormMixin, ModifiableViewMixin
from shuup.admin.supplier_provider import get_supplier
from shuup.admin.toolbar import PostActionButton, Toolbar
from shuup.admin.utils.forms import add_form_errors_as_messages
from shuup.admin.utils.picotable import Column
from shuup.admin.utils.urls import NoModelUrl, get_model_url
from shuup.admin.utils.views import PicotableListView
from shuup.core.excs import NoProductsToShipException, NoShippingAddressException
from shuup.core.models import Order, Product, Shipment, ShipmentProduct, ShipmentStatus, Shop, UnitInterface
from shuup.utils.django_compat import reverse
from shuup.utils.excs import Problem
[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_queryset(self):
shop_ids = Shop.objects.get_for_user(self.request.user).values_list("id", flat=True)
return Order.objects.exclude(deleted=True).filter(shop_id__in=shop_ids)
[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",
),
],
view=self,
)
return context
def _get_supplier_id(self):
return int(self.kwargs["supplier_pk"])
[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 get_success_url(self):
return get_model_url(self.object)
[docs]class ShipmentDeleteView(DetailView):
model = Shipment
context_object_name = "shipment"
[docs] def get_queryset(self):
shop_ids = Shop.objects.get_for_user(self.request.user).values_list("id", flat=True)
return Shipment.objects.filter(order__shop_id__in=shop_ids)
[docs] def get_success_url(self):
return get_model_url(self.get_object().order)
[docs] def get(self, request, *args, **kwargs):
return HttpResponseRedirect(self.get_success_url())
[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(self.get_success_url())
[docs]class ShipmentSetSentView(DetailView):
model = Shipment
context_object_name = "shipment"
[docs] def get_queryset(self):
shop_ids = Shop.objects.get_for_user(self.request.user).values_list("id", flat=True)
return Shipment.objects.filter(order__shop_id__in=shop_ids)
[docs] def get_success_url(self):
if self.request.GET.get("next"):
return self.request.GET["next"]
return get_model_url(self.get_object().order)
[docs] def get(self, request, *args, **kwargs):
return HttpResponseRedirect(self.get_success_url())
[docs] def post(self, request, *args, **kwargs):
shipment = self.get_object()
shipment.set_sent()
messages.success(request, _("Shipment has been marked as sent."))
return HttpResponseRedirect(self.get_success_url())
[docs]class ShipmentListView(PicotableListView):
model = Shipment
template_name = "shuup/admin/orders/shipment_picotable.jinja"
default_columns = [
Column("id", _("ID"), linked=True),
Column("order", _("Order"), display="get_order", raw=True),
Column("get_content", _("Content"), display="get_content", raw=True),
Column("supplier", _("Supplier"), display="get_supplier", raw=True),
Column("tracking_code", _("Tracking Code"), display="tracking_code_url", raw=True),
Column("status", _("Status"), display="create_action_buttons", raw=True),
]
[docs] def tracking_code_url(self, instance):
if instance.tracking_url:
return f'<a target="_blank" ref="noopened" href="{instance.tracking_url}">{instance.tracking_code}</a>'
return instance.tracking_code
[docs] def get_supplier(self, instance):
return instance.supplier.name
[docs] def get_order(self, instance):
try:
order_url = get_model_url(instance.order)
return f'<a href="{order_url}">{str(instance.order)}</a>'
except NoModelUrl:
return str(instance.order)
[docs] def get_content(self, instance):
shipment_products = ShipmentProduct.objects.filter(shipment=instance).select_related(
"product", "product__sales_unit"
)
content = []
for shipment_product in shipment_products:
unit = UnitInterface(shipment_product.product.sales_unit)
quantity = unit.render_quantity(shipment_product.quantity)
content.append(f"{shipment_product.product} ({quantity})")
return ", ".join(content)
def __init__(self):
super().__init__()
self.columns = self.default_columns
[docs] def get_queryset(self):
queryset = (
super()
.get_queryset()
.exclude(status=ShipmentStatus.DELETED)
.select_related("order", "order__shipping_method")
)
supplier = get_supplier(self.request)
if supplier:
queryset = queryset.filter(supplier=supplier)
return queryset
[docs] def get_object_abstract(self, instance, item):
return [
{"text": _("Shipment {shipment_id}").format(shipment_id=item.get("id")), "class": "header"},
{"title": _("Order"), "text": " ", "raw": item.get("order")},
{"title": _("Supplier"), "text": item.get("supplier")},
{"title": _("Content"), "text": item.get("get_content")},
{"title": _("Tracking code"), "text": " ", "raw": item.get("tracking_code")},
{"title": _("Status"), "text": " ", "raw": item.get("status")},
]