mirror of
https://github.com/inventree/InvenTree.git
synced 2025-06-16 12:05:53 +00:00
Adds detail page for ReturnOrder
This commit is contained in:
@ -1122,7 +1122,10 @@ def render_currency(money, decimal_places=None, currency=None, include_symbol=Tr
|
|||||||
include_symbol: Render with the appropriate currency symbol
|
include_symbol: Render with the appropriate currency symbol
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if money is None or money.amount is None:
|
if money in [None, '']:
|
||||||
|
return '-'
|
||||||
|
|
||||||
|
if type(money) is not Money:
|
||||||
return '-'
|
return '-'
|
||||||
|
|
||||||
if currency is not None:
|
if currency is not None:
|
||||||
|
@ -1313,6 +1313,28 @@ class ReturnOrderDetail(RetrieveUpdateDestroyAPI):
|
|||||||
return self.serializer_class(*args, **kwargs)
|
return self.serializer_class(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
class ReturnOrderAttachmentList(AttachmentMixin, ListCreateDestroyAPIView):
|
||||||
|
"""API endpoint for listing (and creating) a ReturnOrderAttachment (file upload)"""
|
||||||
|
|
||||||
|
queryset = models.ReturnOrderAttachment.objects.all()
|
||||||
|
serializer_class = serializers.ReturnOrderAttachmentSerializer
|
||||||
|
|
||||||
|
filter_backends = [
|
||||||
|
rest_filters.DjangoFilterBackend,
|
||||||
|
]
|
||||||
|
|
||||||
|
filterset_fields = [
|
||||||
|
'order',
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class ReturnOrderAttachmentDetail(AttachmentMixin, RetrieveUpdateDestroyAPI):
|
||||||
|
"""Detail endpoint for the ReturnOrderAttachment model"""
|
||||||
|
|
||||||
|
queryset = models.ReturnOrderAttachment.objects.all()
|
||||||
|
serializer_class = serializers.ReturnOrderAttachmentSerializer
|
||||||
|
|
||||||
|
|
||||||
class OrderCalendarExport(ICalFeed):
|
class OrderCalendarExport(ICalFeed):
|
||||||
"""Calendar export for Purchase/Sales Orders
|
"""Calendar export for Purchase/Sales Orders
|
||||||
|
|
||||||
@ -1474,7 +1496,7 @@ order_api_urls = [
|
|||||||
])),
|
])),
|
||||||
|
|
||||||
# Individual purchase order detail URLs
|
# Individual purchase order detail URLs
|
||||||
re_path(r'^(?P<pk>\d+)/', include([
|
path(r'<int:pk>/', include([
|
||||||
re_path(r'^cancel/', PurchaseOrderCancel.as_view(), name='api-po-cancel'),
|
re_path(r'^cancel/', PurchaseOrderCancel.as_view(), name='api-po-cancel'),
|
||||||
re_path(r'^complete/', PurchaseOrderComplete.as_view(), name='api-po-complete'),
|
re_path(r'^complete/', PurchaseOrderComplete.as_view(), name='api-po-complete'),
|
||||||
re_path(r'^issue/', PurchaseOrderIssue.as_view(), name='api-po-issue'),
|
re_path(r'^issue/', PurchaseOrderIssue.as_view(), name='api-po-issue'),
|
||||||
@ -1509,7 +1531,7 @@ order_api_urls = [
|
|||||||
])),
|
])),
|
||||||
|
|
||||||
re_path(r'^shipment/', include([
|
re_path(r'^shipment/', include([
|
||||||
re_path(r'^(?P<pk>\d+)/', include([
|
path(r'<int:pk>/', include([
|
||||||
path('ship/', SalesOrderShipmentComplete.as_view(), name='api-so-shipment-ship'),
|
path('ship/', SalesOrderShipmentComplete.as_view(), name='api-so-shipment-ship'),
|
||||||
re_path(r'^.*$', SalesOrderShipmentDetail.as_view(), name='api-so-shipment-detail'),
|
re_path(r'^.*$', SalesOrderShipmentDetail.as_view(), name='api-so-shipment-detail'),
|
||||||
])),
|
])),
|
||||||
@ -1517,7 +1539,7 @@ order_api_urls = [
|
|||||||
])),
|
])),
|
||||||
|
|
||||||
# Sales order detail view
|
# Sales order detail view
|
||||||
re_path(r'^(?P<pk>\d+)/', include([
|
path(r'<int:pk>/', include([
|
||||||
re_path(r'^allocate/', SalesOrderAllocate.as_view(), name='api-so-allocate'),
|
re_path(r'^allocate/', SalesOrderAllocate.as_view(), name='api-so-allocate'),
|
||||||
re_path(r'^allocate-serials/', SalesOrderAllocateSerials.as_view(), name='api-so-allocate-serials'),
|
re_path(r'^allocate-serials/', SalesOrderAllocateSerials.as_view(), name='api-so-allocate-serials'),
|
||||||
re_path(r'^cancel/', SalesOrderCancel.as_view(), name='api-so-cancel'),
|
re_path(r'^cancel/', SalesOrderCancel.as_view(), name='api-so-cancel'),
|
||||||
@ -1553,6 +1575,11 @@ order_api_urls = [
|
|||||||
# API endpoints for return orders
|
# API endpoints for return orders
|
||||||
re_path(r'^return/', include([
|
re_path(r'^return/', include([
|
||||||
|
|
||||||
|
re_path(r'^attachment/', include([
|
||||||
|
path('<int:pk>/', ReturnOrderAttachmentDetail.as_view(), name='api-return-order-attachment-detail'),
|
||||||
|
re_path(r'^.*$', ReturnOrderAttachmentList.as_view(), name='api-return-order-attachment-list'),
|
||||||
|
])),
|
||||||
|
|
||||||
# Return Order detail
|
# Return Order detail
|
||||||
path('<int:pk>/', ReturnOrderDetail.as_view(), name='api-return-order-detail'),
|
path('<int:pk>/', ReturnOrderDetail.as_view(), name='api-return-order-detail'),
|
||||||
|
|
||||||
|
115
InvenTree/order/templates/order/return_order_base.html
Normal file
115
InvenTree/order/templates/order/return_order_base.html
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
{% extends "page_base.html" %}
|
||||||
|
|
||||||
|
{% load i18n %}
|
||||||
|
{% load static %}
|
||||||
|
{% load inventree_extras %}
|
||||||
|
{% load status_codes %}
|
||||||
|
|
||||||
|
{% block page_title %}
|
||||||
|
{% inventree_title %} | {% trans "Return Order" %}
|
||||||
|
{% endblock page_title %}
|
||||||
|
|
||||||
|
{% block breadcrumbs %}
|
||||||
|
<li class='breadcrumb-item'><a href='{% url "return-order-index" %}'>{% trans "Return Orders" %}</a></li>
|
||||||
|
<li class="breadcrumb-item active" aria-current="page"><a href='{% url "return-order-detail" order.id %}'>{{ order }}</a></li>
|
||||||
|
{% endblock breadcrumbs %}
|
||||||
|
|
||||||
|
{% block thumbnail %}
|
||||||
|
<img class='part-thumb'
|
||||||
|
{% if order.customer and order.customer.image %}
|
||||||
|
src="{{ order.customer.image.url }}"
|
||||||
|
{% else %}
|
||||||
|
src="{% static 'img/blank_image.png' %}"
|
||||||
|
{% endif %}
|
||||||
|
/>
|
||||||
|
{% endblock thumbnail%}
|
||||||
|
|
||||||
|
{% block heading %}
|
||||||
|
{% trans "Return Order" %} {{ order.reference }}
|
||||||
|
{% endblock heading %}
|
||||||
|
|
||||||
|
{% block actions %}
|
||||||
|
{% if user.is_staff and roles.return_order.change %}
|
||||||
|
{% url 'admin:order_returnorder_change' order.pk as url %}
|
||||||
|
{% include "admin_button.html" with url=url %}
|
||||||
|
{% endif %}
|
||||||
|
<!-- TODO: Printing actions -->
|
||||||
|
<!-- TODO: Order actions-->
|
||||||
|
{% endblock actions %}
|
||||||
|
|
||||||
|
{% block details %}
|
||||||
|
|
||||||
|
<table class='table table-striped table-condensed'>
|
||||||
|
<col width='25'>
|
||||||
|
<tr>
|
||||||
|
<td><span class='fas fa-hashtag'></span></td>
|
||||||
|
<td>{% trans "Order Reference" %}</td>
|
||||||
|
<td>{{ order.reference }}{% include "clip.html"%}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><span class='fas fa-info-circle'></span></td>
|
||||||
|
<td>{% trans "Order Description" %}</td>
|
||||||
|
<td>{{ order.description }}{% include "clip.html" %}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><span class='fas fa-info'></span></td>
|
||||||
|
<td>{% trans "Order Status" %}</td>
|
||||||
|
<td>
|
||||||
|
{% return_order_status_label order.status %}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
{% endblock details %}
|
||||||
|
|
||||||
|
{% block details_right %}
|
||||||
|
<table class='table table-striped table-condensed'>
|
||||||
|
<col width='25'>
|
||||||
|
{% if order.customer %}
|
||||||
|
<tr>
|
||||||
|
<td><span class='fas fa-building'></span></td>
|
||||||
|
<td>{% trans "Customer" %}</td>
|
||||||
|
<td><a href="{% url 'company-detail' order.customer.id %}">{{ order.customer.name }}</a>{% include "clip.html"%}</td>
|
||||||
|
</tr>
|
||||||
|
{% endif %}
|
||||||
|
{% if order.customer_reference %}
|
||||||
|
<tr>
|
||||||
|
<td><span class='fas fa-hashtag'></span></td>
|
||||||
|
<td>{% trans "Customer Reference" %}</td>
|
||||||
|
<td>{{ order.customer_reference }}{% include "clip.html"%}</td>
|
||||||
|
</tr>
|
||||||
|
{% endif %}
|
||||||
|
{% if order.link %}
|
||||||
|
<tr>
|
||||||
|
<td><span class='fas fa-link'></span></td>
|
||||||
|
<td>External Link</td>
|
||||||
|
<td><a href="{{ order.link }}">{{ order.link }}</a>{% include "clip.html"%}</td>
|
||||||
|
</tr>
|
||||||
|
{% endif %}
|
||||||
|
<tr>
|
||||||
|
<td><span class='fas fa-calendar-alt'></span></td>
|
||||||
|
<td>{% trans "Created" %}</td>
|
||||||
|
<td>{% render_date order.creation_date %}<span class='badge badge-right rounded-pill bg-dark'>{{ order.created_by }}</span></td>
|
||||||
|
</tr>
|
||||||
|
{% if order.responsible %}
|
||||||
|
<tr>
|
||||||
|
<td><span class='fas fa-users'></span></td>
|
||||||
|
<td>{% trans "Responsible" %}</td>
|
||||||
|
<td>{{ order.responsible }}</td>
|
||||||
|
</tr>
|
||||||
|
{% endif %}
|
||||||
|
</table>
|
||||||
|
{% endblock details_right %}
|
||||||
|
|
||||||
|
{% block js_ready %}
|
||||||
|
{{ block.super }}
|
||||||
|
|
||||||
|
<!-- TODO: Javascript callbacks -->
|
||||||
|
|
||||||
|
{% if report_enabled %}
|
||||||
|
<!-- TODO: Report callbacks -->
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<!-- TODO: Export order callback -->
|
||||||
|
|
||||||
|
{% endblock js_ready %}
|
111
InvenTree/order/templates/order/return_order_detail.html
Normal file
111
InvenTree/order/templates/order/return_order_detail.html
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
{% extends "order/return_order_base.html" %}
|
||||||
|
|
||||||
|
{% load inventree_extras %}
|
||||||
|
{% load status_codes %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% load static %}
|
||||||
|
|
||||||
|
{% block sidebar %}
|
||||||
|
{% include "order/return_order_sidebar.html" %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block page_content %}
|
||||||
|
|
||||||
|
<div class='panel panel-hidden' id='panel-order-details'>
|
||||||
|
<div class='panel-heading'>
|
||||||
|
<h4>{% trans "Order Details" %}</h4>
|
||||||
|
{% include "spacer.html" %}
|
||||||
|
</div>
|
||||||
|
<div class='panel-content'>
|
||||||
|
<!-- TODO: Order details here -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class='panel panel-hidden' id='panel-order-attachments'>
|
||||||
|
<div class='panel-heading'>
|
||||||
|
<div class='d-flex flex-wrap'>
|
||||||
|
<h4>{% trans "Attachments" %}</h4>
|
||||||
|
{% include "spacer.html" %}
|
||||||
|
<div class='btn-group' role='group'>
|
||||||
|
{% include "attachment_button.html" %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class='panel-content'>
|
||||||
|
{% include "attachment_table.html" %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class='panel panel-hidden' id='panel-order-notes'>
|
||||||
|
<div class='panel-heading'>
|
||||||
|
<div class='d-flex flex-wrap'>
|
||||||
|
<h4>{% trans "Order Notes" %}</h4>
|
||||||
|
{% include "spacer.html" %}
|
||||||
|
<div class='btn-group' role='group'>
|
||||||
|
{% include "notes_buttons.html" %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class='panel-content'>
|
||||||
|
<textarea id='order-notes'></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
{% endblock page_content %}
|
||||||
|
|
||||||
|
{% block js_ready %}
|
||||||
|
{{ block.super }}
|
||||||
|
|
||||||
|
// Callback function when the 'details' panel is loaded
|
||||||
|
onPanelLoad('order-details', function() {
|
||||||
|
// TODO
|
||||||
|
});
|
||||||
|
|
||||||
|
// Callback function when the 'notes' panel is loaded
|
||||||
|
onPanelLoad('order-notes', function() {
|
||||||
|
setupNotesField(
|
||||||
|
'order-notes',
|
||||||
|
'{% url "api-return-order-detail" order.pk %}',
|
||||||
|
{
|
||||||
|
{% if roles.purchase_order.change %}
|
||||||
|
editable: true,
|
||||||
|
{% else %}
|
||||||
|
editable: false,
|
||||||
|
{% endif %}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Callback function when the 'attachments' panel is loaded
|
||||||
|
onPanelLoad('order-attachments', function() {
|
||||||
|
enableDragAndDrop(
|
||||||
|
'#attachment-dropzone',
|
||||||
|
'{% url "api-return-order-attachment-list" %}',
|
||||||
|
{
|
||||||
|
data: {
|
||||||
|
order: {{ order.id }},
|
||||||
|
},
|
||||||
|
label: 'attachment',
|
||||||
|
success: function(data, status, xhr) {
|
||||||
|
reloadAttachmentTable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
loadAttachmentTable('{% url "api-return-order-attachment-list" %}', {
|
||||||
|
filters: {
|
||||||
|
order: {{ order.pk }},
|
||||||
|
},
|
||||||
|
fields: {
|
||||||
|
order: {
|
||||||
|
value: {{ order.pk }},
|
||||||
|
hidden: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
enableSidebar('returnorder');
|
||||||
|
|
||||||
|
{% endblock js_ready %}
|
10
InvenTree/order/templates/order/return_order_sidebar.html
Normal file
10
InvenTree/order/templates/order/return_order_sidebar.html
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
{% load i18n %}
|
||||||
|
{% load static %}
|
||||||
|
{% load inventree_extras %}
|
||||||
|
|
||||||
|
{% trans "Order Details" as text %}
|
||||||
|
{% include "sidebar_item.html" with label='order-details' text=text icon="fa-info-circle" %}
|
||||||
|
{% trans "Attachments" as text %}
|
||||||
|
{% include "sidebar_item.html" with label='order-attachments' text=text icon="fa-paperclip" %}
|
||||||
|
{% trans "Notes" as text %}
|
||||||
|
{% include "sidebar_item.html" with label='order-notes' text=text icon="fa-clipboard" %}
|
@ -209,30 +209,32 @@
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
enableDragAndDrop(
|
onPanelLoad('order-attachments', function() {
|
||||||
'#attachment-dropzone',
|
enableDragAndDrop(
|
||||||
'{% url "api-so-attachment-list" %}',
|
'#attachment-dropzone',
|
||||||
{
|
'{% url "api-so-attachment-list" %}',
|
||||||
data: {
|
{
|
||||||
order: {{ order.id }},
|
data: {
|
||||||
},
|
order: {{ order.id }},
|
||||||
label: 'attachment',
|
},
|
||||||
success: function(data, status, xhr) {
|
label: 'attachment',
|
||||||
reloadAttachmentTable();
|
success: function(data, status, xhr) {
|
||||||
|
reloadAttachmentTable();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
);
|
||||||
);
|
|
||||||
|
|
||||||
loadAttachmentTable('{% url "api-so-attachment-list" %}', {
|
loadAttachmentTable('{% url "api-so-attachment-list" %}', {
|
||||||
filters: {
|
filters: {
|
||||||
order: {{ order.pk }},
|
order: {{ order.pk }},
|
||||||
},
|
|
||||||
fields: {
|
|
||||||
order: {
|
|
||||||
value: {{ order.pk }},
|
|
||||||
hidden: true,
|
|
||||||
},
|
},
|
||||||
}
|
fields: {
|
||||||
|
order: {
|
||||||
|
value: {{ order.pk }},
|
||||||
|
hidden: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
loadBuildTable($("#builds-table"), {
|
loadBuildTable($("#builds-table"), {
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
- Detail view of Purchase Orders
|
- Detail view of Purchase Orders
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from django.urls import include, re_path
|
from django.urls import include, path, re_path
|
||||||
|
|
||||||
from . import views
|
from . import views
|
||||||
|
|
||||||
@ -21,7 +21,7 @@ purchase_order_urls = [
|
|||||||
re_path(r'^pricing/', views.LineItemPricing.as_view(), name='line-pricing'),
|
re_path(r'^pricing/', views.LineItemPricing.as_view(), name='line-pricing'),
|
||||||
|
|
||||||
# Display detail view for a single purchase order
|
# Display detail view for a single purchase order
|
||||||
re_path(r'^(?P<pk>\d+)/', include(purchase_order_detail_urls)),
|
path(r'<int:pk>/', include(purchase_order_detail_urls)),
|
||||||
|
|
||||||
# Display complete list of purchase orders
|
# Display complete list of purchase orders
|
||||||
re_path(r'^.*$', views.PurchaseOrderIndex.as_view(), name='purchase-order-index'),
|
re_path(r'^.*$', views.PurchaseOrderIndex.as_view(), name='purchase-order-index'),
|
||||||
@ -35,7 +35,7 @@ sales_order_detail_urls = [
|
|||||||
|
|
||||||
sales_order_urls = [
|
sales_order_urls = [
|
||||||
# Display detail view for a single SalesOrder
|
# Display detail view for a single SalesOrder
|
||||||
re_path(r'^(?P<pk>\d+)/', include(sales_order_detail_urls)),
|
path(r'<int:pk>/', include(sales_order_detail_urls)),
|
||||||
|
|
||||||
# Display list of all sales orders
|
# Display list of all sales orders
|
||||||
re_path(r'^.*$', views.SalesOrderIndex.as_view(), name='sales-order-index'),
|
re_path(r'^.*$', views.SalesOrderIndex.as_view(), name='sales-order-index'),
|
||||||
@ -43,6 +43,7 @@ sales_order_urls = [
|
|||||||
|
|
||||||
|
|
||||||
return_order_urls = [
|
return_order_urls = [
|
||||||
|
path(r'<int:pk>/', views.ReturnOrderDetail.as_view(), name='return-order-detail'),
|
||||||
|
|
||||||
# Display list of all return orders
|
# Display list of all return orders
|
||||||
re_path(r'^.*$', views.ReturnOrderIndex.as_view(), name='return-order-index'),
|
re_path(r'^.*$', views.ReturnOrderIndex.as_view(), name='return-order-index'),
|
||||||
|
@ -75,6 +75,14 @@ class SalesOrderDetail(InvenTreeRoleMixin, InvenTreePluginViewMixin, DetailView)
|
|||||||
template_name = 'order/sales_order_detail.html'
|
template_name = 'order/sales_order_detail.html'
|
||||||
|
|
||||||
|
|
||||||
|
class ReturnOrderDetail(InvenTreeRoleMixin, InvenTreePluginViewMixin, DetailView):
|
||||||
|
"""Detail view for a ReturnOrder object"""
|
||||||
|
|
||||||
|
context_object_name = 'order'
|
||||||
|
queryset = ReturnOrder.objects.all()
|
||||||
|
template_name = 'order/return_order_detail.html'
|
||||||
|
|
||||||
|
|
||||||
class PurchaseOrderUpload(FileManagementFormView):
|
class PurchaseOrderUpload(FileManagementFormView):
|
||||||
"""PurchaseOrder: Upload file, match to fields and parts (using multi-Step form)"""
|
"""PurchaseOrder: Upload file, match to fields and parts (using multi-Step form)"""
|
||||||
|
|
||||||
|
@ -4,7 +4,8 @@ from django import template
|
|||||||
from django.utils.safestring import mark_safe
|
from django.utils.safestring import mark_safe
|
||||||
|
|
||||||
from InvenTree.status_codes import (BuildStatus, PurchaseOrderStatus,
|
from InvenTree.status_codes import (BuildStatus, PurchaseOrderStatus,
|
||||||
SalesOrderStatus, StockStatus)
|
ReturnOrderStatus, SalesOrderStatus,
|
||||||
|
StockStatus)
|
||||||
|
|
||||||
register = template.Library()
|
register = template.Library()
|
||||||
|
|
||||||
@ -21,6 +22,12 @@ def sales_order_status_label(key, *args, **kwargs):
|
|||||||
return mark_safe(SalesOrderStatus.render(key, large=kwargs.get('large', False)))
|
return mark_safe(SalesOrderStatus.render(key, large=kwargs.get('large', False)))
|
||||||
|
|
||||||
|
|
||||||
|
@register.simple_tag
|
||||||
|
def return_order_status_label(key, *args, **kwargs):
|
||||||
|
"""Render a ReturnOrder status label"""
|
||||||
|
return mark_safe(ReturnOrderStatus.render(key, large=kwargs.get('large', False)))
|
||||||
|
|
||||||
|
|
||||||
@register.simple_tag
|
@register.simple_tag
|
||||||
def stock_status_label(key, *args, **kwargs):
|
def stock_status_label(key, *args, **kwargs):
|
||||||
"""Render a StockItem status label."""
|
"""Render a StockItem status label."""
|
||||||
|
Reference in New Issue
Block a user