# -*- 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
from django import forms
from django.contrib import messages
from django.core.urlresolvers import reverse
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, URLActionButton
from shoop.admin.utils.urls import get_model_url
from shoop.core.excs import (
NoRefundToCreateException, RefundExceedsAmountException
)
from shoop.core.models import Order
from shoop.utils.money import Money
[docs]class OrderCreateRefundView(UpdateView):
model = Order
template_name = "shoop/admin/orders/create_refund.jinja"
context_object_name = "order"
form_class = forms.formset_factory(RefundForm, extra=1)
[docs] def get_context_data(self, **kwargs):
context = super(OrderCreateRefundView, self).get_context_data(**kwargs)
context["title"] = _("Create Refund -- %s") % context["order"]
context["toolbar"] = Toolbar([
PostActionButton(
icon="fa fa-check-circle",
form_id="create_refund",
text=_("Create Refund"),
extra_css_class="btn-success",
),
URLActionButton(
url=reverse("shoop_admin:order.create-full-refund", kwargs={"pk": self.object.pk}),
icon="fa fa-dollar",
text=_("Refund Entire Order"),
extra_css_class="btn-info",
disable_reason=_("This order already has existing refunds") if self.object.has_refunds() else None
),
])
# Setting the line_numbers choices dynamically creates issues with the blank formset,
# So adding that to the context to be rendered manually
context["line_number_choices"] = self._get_line_number_choices()
context["json_line_data"] = [self._get_line_data(self.object.shop, line) for line in self.object.lines.all()]
return context
def _get_line_data(self, shop, line):
total_price = line.taxful_price.value if shop.prices_include_tax else line.taxless_price.value
base_data = {
"id": line.id,
"type": "other" if line.quantity else "text",
"text": line.text,
"quantity": line.quantity,
"sku": line.sku,
"baseUnitPrice": line.base_unit_price.value,
"unitPrice": total_price / line.quantity if line.quantity else 0,
"unitPriceIncludesTax": shop.prices_include_tax,
"errors": "",
"step": ""
}
if line.product:
shop_product = line.product.get_shop_instance(shop)
supplier = shop_product.suppliers.first()
stock_status = supplier.get_stock_status(line.product.pk) if supplier else None
base_data.update({
"type": "product",
"product": {
"id": line.product.pk,
"text": line.product.name
},
"step": shop_product.purchase_multiple,
"logicalCount": stock_status.logical_count if stock_status else 0,
"physicalCount": stock_status.physical_count if stock_status else 0,
"salesDecimals": line.product.sales_unit.decimals if line.product.sales_unit else 0,
"salesUnit": line.product.sales_unit.short_name if line.product.sales_unit else ""
})
return base_data
def _get_refundable_line_numbers(self):
return [line.ordering for line in self.object.lines.all() if line.max_refundable_amount.value > 0]
def _get_line_number_choices(self):
return [("", "---")] + [((i), (i+1)) for i in self._get_refundable_line_numbers()]
def get_form(self, form_class):
formset = super(OrderCreateRefundView, self).get_form(form_class)
# Line orderings are zero-indexed, but shouldn't display that way
choices = self._get_line_number_choices()
for form in formset.forms:
form.fields["line_number"].choices = choices
formset.empty_form.fields["line_number"].choices = choices
return formset
def _get_refund_line_info(self, order, data):
refund_line_info = {}
total_amount = Money(0, order.currency)
amount_value = data.get("amount", 0)
line_number = data.get("line_number")
quantity = data.get("quantity", 0)
restock_products = data.get("restock_products")
if amount_value:
amount = Money(amount_value, order.currency)
refund_line_info["amount"] = amount
total_amount += amount
if line_number:
line = order.lines.get(ordering=line_number)
refund_line_info["line"] = line
if data.get("quantity", None):
unit_price = line.base_unit_price.amount
quantity = data["quantity"]
calculated_refund_amount = unit_price * quantity
refund_line_info["quantity"] = quantity
total_amount += calculated_refund_amount
# Add taxes to refund or somehow otherwise include it
# Check to make sure total amount isn't more than line total
if total_amount > line.max_refundable_amount:
raise RefundExceedsAmountException
refund_line_info["restock_products"] = bool(restock_products)
return refund_line_info if total_amount else {}
[docs]class OrderCreateFullRefundView(UpdateView):
model = Order
template_name = "shoop/admin/orders/create_full_refund.jinja"
context_object_name = "order"
form_class = FullRefundConfirmationForm
[docs] def get_context_data(self, **kwargs):
context = super(OrderCreateFullRefundView, self).get_context_data(**kwargs)
context["title"] = _("Create Full Refund -- %s") % context["order"]
context["toolbar"] = Toolbar([
URLActionButton(
url=reverse("shoop_admin:order.create-refund", kwargs={"pk": self.object.pk}),
icon="fa fa-check-circle",
text=_("Cancel"),
extra_css_class="btn-danger",
),
])
return context