diff --git a/InvenTree/order/templates/order/order_base.html b/InvenTree/order/templates/order/order_base.html
index d2a5bb9871..63d415afa2 100644
--- a/InvenTree/order/templates/order/order_base.html
+++ b/InvenTree/order/templates/order/order_base.html
@@ -10,7 +10,7 @@
{% endblock %}
{% block breadcrumbs %}
-
{% trans "Purchase Orders" %}
+{% trans "Purchase Orders" %}
{{ order }}
{% endblock %}
diff --git a/InvenTree/order/templates/order/return_orders.html b/InvenTree/order/templates/order/return_orders.html
new file mode 100644
index 0000000000..c2be127342
--- /dev/null
+++ b/InvenTree/order/templates/order/return_orders.html
@@ -0,0 +1,65 @@
+{% extends "page_base.html" %}
+
+{% load inventree_extras %}
+{% load static %}
+{% load i18n %}
+
+{% block page_title %}
+{% inventree_title %} | {% trans "Return Orders" %}
+{% endblock %}
+
+{% block breadcrumb_list %}
+{% endblock %}
+
+{% block heading %}
+{% trans "Return Orders" %}
+{% endblock %}
+
+
+{% block actions %}
+{% if roles.returns.add %}
+
+{% endif %}
+{% endblock actions %}
+
+{% block page_info %}
+
+
+
+{% endblock page_info %}
+
+{% block js_ready %}
+{{ block.super }}
+
+loadReturnOrderTable('#return-order-table', {
+});
+
+{% if report_enabled %}
+
+{% endif %}
+
+$('#return-order-create').click(function() {
+ createReturnOrder();
+});
+
+{% endblock js_ready %}
diff --git a/InvenTree/order/templates/order/sales_order_base.html b/InvenTree/order/templates/order/sales_order_base.html
index 20acc35379..15278bfbb3 100644
--- a/InvenTree/order/templates/order/sales_order_base.html
+++ b/InvenTree/order/templates/order/sales_order_base.html
@@ -10,7 +10,7 @@
{% endblock %}
{% block breadcrumbs %}
-{% trans "Sales Orders" %}
+{% trans "Sales Orders" %}
{{ order }}
{% endblock %}
diff --git a/InvenTree/order/test_views.py b/InvenTree/order/test_views.py
index cadd2914ad..cec085cf17 100644
--- a/InvenTree/order/test_views.py
+++ b/InvenTree/order/test_views.py
@@ -32,7 +32,7 @@ class OrderListTest(OrderViewTestCase):
"""Unit tests for the PurchaseOrder index page"""
def test_order_list(self):
"""Tests for the PurchaseOrder index page"""
- response = self.client.get(reverse('po-index'))
+ response = self.client.get(reverse('purchase-order-index'))
self.assertEqual(response.status_code, 200)
diff --git a/InvenTree/order/urls.py b/InvenTree/order/urls.py
index 278914bd75..aca666702d 100644
--- a/InvenTree/order/urls.py
+++ b/InvenTree/order/urls.py
@@ -24,7 +24,7 @@ purchase_order_urls = [
re_path(r'^(?P\d+)/', include(purchase_order_detail_urls)),
# Display complete list of purchase orders
- re_path(r'^.*$', views.PurchaseOrderIndex.as_view(), name='po-index'),
+ re_path(r'^.*$', views.PurchaseOrderIndex.as_view(), name='purchase-order-index'),
]
sales_order_detail_urls = [
@@ -38,10 +38,19 @@ sales_order_urls = [
re_path(r'^(?P\d+)/', include(sales_order_detail_urls)),
# Display list of all sales orders
- re_path(r'^.*$', views.SalesOrderIndex.as_view(), name='so-index'),
+ re_path(r'^.*$', views.SalesOrderIndex.as_view(), name='sales-order-index'),
]
+
+return_order_urls = [
+
+ # Display list of all return orders
+ re_path(r'^.*$', views.ReturnOrderIndex.as_view(), name='return-order-index'),
+]
+
+
order_urls = [
re_path(r'^purchase-order/', include(purchase_order_urls)),
re_path(r'^sales-order/', include(sales_order_urls)),
+ re_path(r'^return-order/', include(return_order_urls)),
]
diff --git a/InvenTree/order/views.py b/InvenTree/order/views.py
index b3909971e0..7027f0a0f3 100644
--- a/InvenTree/order/views.py
+++ b/InvenTree/order/views.py
@@ -24,8 +24,8 @@ from plugin.views import InvenTreePluginViewMixin
from . import forms as order_forms
from .admin import PurchaseOrderLineItemResource, SalesOrderLineItemResource
-from .models import (PurchaseOrder, PurchaseOrderLineItem, SalesOrder,
- SalesOrderLineItem)
+from .models import (PurchaseOrder, PurchaseOrderLineItem, ReturnOrder,
+ SalesOrder, SalesOrderLineItem)
logger = logging.getLogger("inventree")
@@ -51,6 +51,14 @@ class SalesOrderIndex(InvenTreeRoleMixin, ListView):
context_object_name = 'orders'
+class ReturnOrderIndex(InvenTreeRoleMixin, ListView):
+ """ReturnOrder index (list) view"""
+
+ model = ReturnOrder
+ template_name = 'order/return_orders.html'
+ context_object_name = 'orders'
+
+
class PurchaseOrderDetail(InvenTreeRoleMixin, InvenTreePluginViewMixin, DetailView):
"""Detail view for a PurchaseOrder object."""
diff --git a/InvenTree/templates/js/translated/order.js b/InvenTree/templates/js/translated/order.js
index 1ec8b48702..3faf789afe 100644
--- a/InvenTree/templates/js/translated/order.js
+++ b/InvenTree/templates/js/translated/order.js
@@ -29,6 +29,7 @@
completePendingShipments,
createPurchaseOrder,
createPurchaseOrderLineItem,
+ createReturnOrder,
createSalesOrder,
createSalesOrderLineItem,
createSalesOrderShipment,
@@ -41,6 +42,7 @@
loadPurchaseOrderLineItemTable,
loadPurchaseOrderExtraLineTable
loadPurchaseOrderTable,
+ loadReturnOrderTable,
loadSalesOrderAllocationTable,
loadSalesOrderLineItemTable,
loadSalesOrderExtraLineTable
@@ -536,9 +538,7 @@ function salesOrderFields(options={}) {
title: '{% trans "Add Customer" %}',
fields: function() {
var fields = companyFormFields();
-
fields.is_customer.value = true;
-
return fields;
}
}
@@ -573,10 +573,10 @@ function createSalesOrder(options={}) {
constructForm('{% url "api-so-list" %}', {
method: 'POST',
fields: fields,
+ title: '{% trans "Create Sales Order" %}',
onSuccess: function(data) {
location.href = `/order/sales-order/${data.pk}/`;
},
- title: '{% trans "Create Sales Order" %}',
});
}
@@ -4662,3 +4662,163 @@ function loadSalesOrderExtraLineTable(table, options={}) {
columns: columns,
});
}
+
+
+/*
+ * Construct a set of fields for a ReturnOrder form
+ */
+function returnOrderFields(options={}) {
+
+ let fields = {
+ reference: {
+ icon: 'fa-hashtag',
+ },
+ description: {},
+ customer: {
+ icon: 'fa-user-tie',
+ secondary: {
+ title: '{% trans "Add Customer" %}',
+ fields: function() {
+ var fields = companyFormFields();
+ fields.is_customer.value = true;
+ return fields;
+ }
+ }
+ },
+ customer_reference: {},
+ link: {
+ icon: 'fa-link',
+ },
+ responsible: {
+ icon: 'fa-user',
+ }
+ };
+
+ return fields;
+}
+
+
+/*
+ * Create a new Return Order
+ */
+function createReturnOrder(options={}) {
+ let fields = returnOrderFields(options);
+
+ if (options.customer) {
+ fields.customer.value = options.customer;
+ }
+
+ constructForm('{% url "api-return-order-list" %}', {
+ method: 'POST',
+ fields: fields,
+ title: '{% trans "Create Return Order" %}',
+ onSuccess: function(data) {
+ location.href = `/order/return-order/${data.pk}/`;
+ },
+ });
+}
+
+
+/*
+ * Load a table of return orders
+ */
+function loadReturnOrderTable(table, options={}) {
+
+ // Ensure the table starts in a known state
+ $(table).bootstrapTable('destroy');
+
+ options.params = options.params || {};
+ options.params['customer_detail'] = true;
+
+ var filters = loadTableFilters('returnorder');
+
+ for (var key in options.params) {
+ filters[key] = options.params[key];
+ }
+
+ setupFilterList('returnorder', $(table), '#filter-list-returnorder', {download: true});
+
+ let display_mode = inventreeLoad('returnorder-table-display-mode', 'list');
+
+ let is_calendar = display_mode == 'calendar';
+
+ $(table).inventreeTable({
+ url: '{% url "api-return-order-list" %}',
+ queryParams: filters,
+ name: 'returnorder',
+ sidePagination: 'server',
+ original: options.params,
+ showColumns: !is_calendar,
+ search: !is_calendar,
+ showCustomViewButton: false,
+ showCustomView: is_calendar,
+ disablePagination: is_calendar,
+ formatNoMatches: function() {
+ return '{% trans "No return orders found" %}';
+ },
+ onRefresh: function() {
+ loadReturnOrderTable(table, options);
+ },
+ onLoadSuccess: function() {
+ // TODO
+ },
+ columns: [
+ {
+ title: '',
+ checkbox: true,
+ visible: true,
+ switchable: false,
+ },
+ {
+ sortable: true,
+ field: 'reference',
+ title: '{% trans "Return Order" %}',
+ formatter: function(value, row) {
+ var html = renderLink(value, `/order/return-order/${row.pk}/`);
+ return html;
+ },
+ },
+ {
+ sortable: true,
+ sortName: 'customer__name',
+ field: 'customer_detail',
+ title: '{% trans "Customer" %}',
+ formatter: function(value, row) {
+
+ if (!row.customer_detail) {
+ return '{% trans "Invalid Customer" %}';
+ }
+
+ return imageHoverIcon(row.customer_detail.image) + renderLink(row.customer_detail.name, `/company/${row.customer}/sales-orders/`);
+ }
+ },
+ {
+ sortable: true,
+ field: 'customer_reference',
+ title: '{% trans "Customer Reference" %}',
+ },
+ {
+ sortable: false,
+ field: 'description',
+ title: '{% trans "Description" %}',
+ },
+ {
+ sortable: true,
+ field: 'status',
+ title: '{% trans "Status" %}',
+ formatter: function(value, row) {
+ return 'todo';
+ return salesOrderStatusDisplay(row.status);
+ }
+ },
+ {
+ sortable: true,
+ field: 'creation_date',
+ title: '{% trans "Creation Date" %}',
+ formatter: function(value) {
+ return renderDate(value);
+ }
+ },
+ ]
+ });
+}
diff --git a/InvenTree/templates/navbar.html b/InvenTree/templates/navbar.html
index 620aaf3eff..cd660fa893 100644
--- a/InvenTree/templates/navbar.html
+++ b/InvenTree/templates/navbar.html
@@ -47,18 +47,23 @@
{% endif %}
- {% if roles.sales_order.view %}
+ {% if roles.sales_order.view or roles.returns.view %}
{% endif %}