Merge remote-tracking branch 'inventree/master'

This commit is contained in:
Oliver Walters 2019-12-05 16:36:23 +11:00
commit 0e57a4caec
13 changed files with 205 additions and 106 deletions

View File

@ -17,7 +17,7 @@ from django.db.models import Sum
from django.apps import apps
from django.urls import reverse
from django.conf import settings
from django.contrib.staticfiles.templatetags.staticfiles import static
from django.conf.urls.static import static
from InvenTree.fields import InvenTreeURLField
from InvenTree.status_codes import OrderStatus

View File

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2019-11-18 23:32+0000\n"
"POT-Creation-Date: 2019-12-04 23:28+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@ -18,7 +18,7 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: InvenTree/helpers.py:175 order/models.py:159 order/models.py:204
#: InvenTree/helpers.py:175 order/models.py:159 order/models.py:210
msgid "Invalid quantity provided"
msgstr ""
@ -211,7 +211,7 @@ msgstr ""
#: build/templates/build/allocate_edit.html:19
#: build/templates/build/allocate_view.html:17
#: order/templates/order/purchase_order_detail.html:104
#: order/templates/order/purchase_order_detail.html:107
msgid "Part"
msgstr ""
@ -238,7 +238,7 @@ msgid "Order Parts"
msgstr ""
#: build/templates/build/allocate_view.html:18
#: order/templates/order/purchase_order_detail.html:105
#: order/templates/order/purchase_order_detail.html:108
#: part/templates/part/detail.html:33
msgid "Description"
msgstr ""
@ -298,10 +298,14 @@ msgid "Place order"
msgstr ""
#: order/forms.py:32
msgid "Cancel order"
msgid "Mark order as complete"
msgstr ""
#: order/forms.py:43
msgid "Cancel order"
msgstr ""
#: order/forms.py:54
msgid "Receive parts to this location"
msgstr ""
@ -325,7 +329,7 @@ msgstr ""
msgid "Company"
msgstr ""
#: order/models.py:157 order/models.py:202 part/views.py:1032
#: order/models.py:157 order/models.py:208 part/views.py:1032
#: stock/models.py:438
msgid "Quantity must be greater than zero"
msgstr ""
@ -334,84 +338,84 @@ msgstr ""
msgid "Part supplier must match PO supplier"
msgstr ""
#: order/models.py:197
#: order/models.py:203
msgid "Lines can only be received against an order marked as 'Placed'"
msgstr ""
#: order/models.py:246
#: order/models.py:252
msgid "Item quantity"
msgstr ""
#: order/models.py:248
#: order/models.py:254
msgid "Line item reference"
msgstr ""
#: order/models.py:250
#: order/models.py:256
msgid "Line item notes"
msgstr ""
#: order/models.py:276 stock/templates/stock/item.html:107
#: order/models.py:282 stock/templates/stock/item.html:107
msgid "Purchase Order"
msgstr ""
#: order/models.py:285
#: order/models.py:291
msgid "Supplier part"
msgstr ""
#: order/models.py:288
#: order/models.py:294
msgid "Number of items received"
msgstr ""
#: order/templates/order/purchase_order_detail.html:60
#: order/templates/order/purchase_order_detail.html:63
msgid "Purchase Order Details"
msgstr ""
#: order/templates/order/purchase_order_detail.html:63
#: order/templates/order/purchase_order_detail.html:66
#: stock/templates/stock/item.html:125
msgid "Supplier"
msgstr ""
#: order/templates/order/purchase_order_detail.html:67
#: order/templates/order/purchase_order_detail.html:70
#: stock/templates/stock/item.html:146
msgid "Status"
msgstr ""
#: order/templates/order/purchase_order_detail.html:71
#: order/templates/order/purchase_order_detail.html:74
msgid "Created"
msgstr ""
#: order/templates/order/purchase_order_detail.html:76
#: order/templates/order/purchase_order_detail.html:79
msgid "Issued"
msgstr ""
#: order/templates/order/purchase_order_detail.html:82
#: order/templates/order/purchase_order_detail.html:110
#: order/templates/order/purchase_order_detail.html:85
#: order/templates/order/purchase_order_detail.html:113
msgid "Received"
msgstr ""
#: order/templates/order/purchase_order_detail.html:103
#: order/templates/order/purchase_order_detail.html:106
msgid "Line"
msgstr ""
#: order/templates/order/purchase_order_detail.html:106
#: order/templates/order/purchase_order_detail.html:109
msgid "Order Code"
msgstr ""
#: order/templates/order/purchase_order_detail.html:107
#: order/templates/order/purchase_order_detail.html:110
msgid "Reference"
msgstr ""
#: order/templates/order/purchase_order_detail.html:108
#: order/templates/order/purchase_order_detail.html:111
#: stock/templates/stock/item.html:89
#: stock/templates/stock/stock_adjust.html:20
msgid "Quantity"
msgstr ""
#: order/templates/order/purchase_order_detail.html:112
#: order/templates/order/purchase_order_detail.html:115
msgid "Note"
msgstr ""
#: order/templates/order/purchase_order_detail.html:165
#: order/templates/order/purchase_order_detail.html:168
#: part/templates/part/detail.html:152 stock/templates/stock/item.html:151
msgid "Notes"
msgstr ""
@ -424,15 +428,15 @@ msgstr ""
msgid "Confirm order placement"
msgstr ""
#: order/views.py:695
#: order/views.py:731
msgid "Invalid Purchase Order"
msgstr ""
#: order/views.py:703
#: order/views.py:739
msgid "Supplier must match for Part and Order"
msgstr ""
#: order/views.py:708
#: order/views.py:744
msgid "Invalid SupplierPart selection"
msgstr ""

View File

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2019-11-18 23:32+0000\n"
"POT-Creation-Date: 2019-12-04 23:28+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@ -18,7 +18,7 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: InvenTree/helpers.py:175 order/models.py:159 order/models.py:204
#: InvenTree/helpers.py:175 order/models.py:159 order/models.py:210
msgid "Invalid quantity provided"
msgstr ""
@ -211,7 +211,7 @@ msgstr ""
#: build/templates/build/allocate_edit.html:19
#: build/templates/build/allocate_view.html:17
#: order/templates/order/purchase_order_detail.html:104
#: order/templates/order/purchase_order_detail.html:107
msgid "Part"
msgstr ""
@ -238,7 +238,7 @@ msgid "Order Parts"
msgstr ""
#: build/templates/build/allocate_view.html:18
#: order/templates/order/purchase_order_detail.html:105
#: order/templates/order/purchase_order_detail.html:108
#: part/templates/part/detail.html:33
msgid "Description"
msgstr ""
@ -298,10 +298,14 @@ msgid "Place order"
msgstr ""
#: order/forms.py:32
msgid "Cancel order"
msgid "Mark order as complete"
msgstr ""
#: order/forms.py:43
msgid "Cancel order"
msgstr ""
#: order/forms.py:54
msgid "Receive parts to this location"
msgstr ""
@ -325,7 +329,7 @@ msgstr ""
msgid "Company"
msgstr ""
#: order/models.py:157 order/models.py:202 part/views.py:1032
#: order/models.py:157 order/models.py:208 part/views.py:1032
#: stock/models.py:438
msgid "Quantity must be greater than zero"
msgstr ""
@ -334,84 +338,84 @@ msgstr ""
msgid "Part supplier must match PO supplier"
msgstr ""
#: order/models.py:197
#: order/models.py:203
msgid "Lines can only be received against an order marked as 'Placed'"
msgstr ""
#: order/models.py:246
#: order/models.py:252
msgid "Item quantity"
msgstr ""
#: order/models.py:248
#: order/models.py:254
msgid "Line item reference"
msgstr ""
#: order/models.py:250
#: order/models.py:256
msgid "Line item notes"
msgstr ""
#: order/models.py:276 stock/templates/stock/item.html:107
#: order/models.py:282 stock/templates/stock/item.html:107
msgid "Purchase Order"
msgstr ""
#: order/models.py:285
#: order/models.py:291
msgid "Supplier part"
msgstr ""
#: order/models.py:288
#: order/models.py:294
msgid "Number of items received"
msgstr ""
#: order/templates/order/purchase_order_detail.html:60
#: order/templates/order/purchase_order_detail.html:63
msgid "Purchase Order Details"
msgstr ""
#: order/templates/order/purchase_order_detail.html:63
#: order/templates/order/purchase_order_detail.html:66
#: stock/templates/stock/item.html:125
msgid "Supplier"
msgstr ""
#: order/templates/order/purchase_order_detail.html:67
#: order/templates/order/purchase_order_detail.html:70
#: stock/templates/stock/item.html:146
msgid "Status"
msgstr ""
#: order/templates/order/purchase_order_detail.html:71
#: order/templates/order/purchase_order_detail.html:74
msgid "Created"
msgstr ""
#: order/templates/order/purchase_order_detail.html:76
#: order/templates/order/purchase_order_detail.html:79
msgid "Issued"
msgstr ""
#: order/templates/order/purchase_order_detail.html:82
#: order/templates/order/purchase_order_detail.html:110
#: order/templates/order/purchase_order_detail.html:85
#: order/templates/order/purchase_order_detail.html:113
msgid "Received"
msgstr ""
#: order/templates/order/purchase_order_detail.html:103
#: order/templates/order/purchase_order_detail.html:106
msgid "Line"
msgstr ""
#: order/templates/order/purchase_order_detail.html:106
#: order/templates/order/purchase_order_detail.html:109
msgid "Order Code"
msgstr ""
#: order/templates/order/purchase_order_detail.html:107
#: order/templates/order/purchase_order_detail.html:110
msgid "Reference"
msgstr ""
#: order/templates/order/purchase_order_detail.html:108
#: order/templates/order/purchase_order_detail.html:111
#: stock/templates/stock/item.html:89
#: stock/templates/stock/stock_adjust.html:20
msgid "Quantity"
msgstr ""
#: order/templates/order/purchase_order_detail.html:112
#: order/templates/order/purchase_order_detail.html:115
msgid "Note"
msgstr ""
#: order/templates/order/purchase_order_detail.html:165
#: order/templates/order/purchase_order_detail.html:168
#: part/templates/part/detail.html:152 stock/templates/stock/item.html:151
msgid "Notes"
msgstr ""
@ -424,15 +428,15 @@ msgstr ""
msgid "Confirm order placement"
msgstr ""
#: order/views.py:695
#: order/views.py:731
msgid "Invalid Purchase Order"
msgstr ""
#: order/views.py:703
#: order/views.py:739
msgid "Supplier must match for Part and Order"
msgstr ""
#: order/views.py:708
#: order/views.py:744
msgid "Invalid SupplierPart selection"
msgstr ""

View File

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2019-11-18 23:32+0000\n"
"POT-Creation-Date: 2019-12-04 23:28+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@ -18,7 +18,7 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: InvenTree/helpers.py:175 order/models.py:159 order/models.py:204
#: InvenTree/helpers.py:175 order/models.py:159 order/models.py:210
msgid "Invalid quantity provided"
msgstr ""
@ -211,7 +211,7 @@ msgstr ""
#: build/templates/build/allocate_edit.html:19
#: build/templates/build/allocate_view.html:17
#: order/templates/order/purchase_order_detail.html:104
#: order/templates/order/purchase_order_detail.html:107
msgid "Part"
msgstr ""
@ -238,7 +238,7 @@ msgid "Order Parts"
msgstr ""
#: build/templates/build/allocate_view.html:18
#: order/templates/order/purchase_order_detail.html:105
#: order/templates/order/purchase_order_detail.html:108
#: part/templates/part/detail.html:33
msgid "Description"
msgstr ""
@ -298,10 +298,14 @@ msgid "Place order"
msgstr ""
#: order/forms.py:32
msgid "Cancel order"
msgid "Mark order as complete"
msgstr ""
#: order/forms.py:43
msgid "Cancel order"
msgstr ""
#: order/forms.py:54
msgid "Receive parts to this location"
msgstr ""
@ -325,7 +329,7 @@ msgstr ""
msgid "Company"
msgstr ""
#: order/models.py:157 order/models.py:202 part/views.py:1032
#: order/models.py:157 order/models.py:208 part/views.py:1032
#: stock/models.py:438
msgid "Quantity must be greater than zero"
msgstr ""
@ -334,84 +338,84 @@ msgstr ""
msgid "Part supplier must match PO supplier"
msgstr ""
#: order/models.py:197
#: order/models.py:203
msgid "Lines can only be received against an order marked as 'Placed'"
msgstr ""
#: order/models.py:246
#: order/models.py:252
msgid "Item quantity"
msgstr ""
#: order/models.py:248
#: order/models.py:254
msgid "Line item reference"
msgstr ""
#: order/models.py:250
#: order/models.py:256
msgid "Line item notes"
msgstr ""
#: order/models.py:276 stock/templates/stock/item.html:107
#: order/models.py:282 stock/templates/stock/item.html:107
msgid "Purchase Order"
msgstr ""
#: order/models.py:285
#: order/models.py:291
msgid "Supplier part"
msgstr ""
#: order/models.py:288
#: order/models.py:294
msgid "Number of items received"
msgstr ""
#: order/templates/order/purchase_order_detail.html:60
#: order/templates/order/purchase_order_detail.html:63
msgid "Purchase Order Details"
msgstr ""
#: order/templates/order/purchase_order_detail.html:63
#: order/templates/order/purchase_order_detail.html:66
#: stock/templates/stock/item.html:125
msgid "Supplier"
msgstr ""
#: order/templates/order/purchase_order_detail.html:67
#: order/templates/order/purchase_order_detail.html:70
#: stock/templates/stock/item.html:146
msgid "Status"
msgstr ""
#: order/templates/order/purchase_order_detail.html:71
#: order/templates/order/purchase_order_detail.html:74
msgid "Created"
msgstr ""
#: order/templates/order/purchase_order_detail.html:76
#: order/templates/order/purchase_order_detail.html:79
msgid "Issued"
msgstr ""
#: order/templates/order/purchase_order_detail.html:82
#: order/templates/order/purchase_order_detail.html:110
#: order/templates/order/purchase_order_detail.html:85
#: order/templates/order/purchase_order_detail.html:113
msgid "Received"
msgstr ""
#: order/templates/order/purchase_order_detail.html:103
#: order/templates/order/purchase_order_detail.html:106
msgid "Line"
msgstr ""
#: order/templates/order/purchase_order_detail.html:106
#: order/templates/order/purchase_order_detail.html:109
msgid "Order Code"
msgstr ""
#: order/templates/order/purchase_order_detail.html:107
#: order/templates/order/purchase_order_detail.html:110
msgid "Reference"
msgstr ""
#: order/templates/order/purchase_order_detail.html:108
#: order/templates/order/purchase_order_detail.html:111
#: stock/templates/stock/item.html:89
#: stock/templates/stock/stock_adjust.html:20
msgid "Quantity"
msgstr ""
#: order/templates/order/purchase_order_detail.html:112
#: order/templates/order/purchase_order_detail.html:115
msgid "Note"
msgstr ""
#: order/templates/order/purchase_order_detail.html:165
#: order/templates/order/purchase_order_detail.html:168
#: part/templates/part/detail.html:152 stock/templates/stock/item.html:151
msgid "Notes"
msgstr ""
@ -424,15 +428,15 @@ msgstr ""
msgid "Confirm order placement"
msgstr ""
#: order/views.py:695
#: order/views.py:731
msgid "Invalid Purchase Order"
msgstr ""
#: order/views.py:703
#: order/views.py:739
msgid "Supplier must match for Part and Order"
msgstr ""
#: order/views.py:708
#: order/views.py:744
msgid "Invalid SupplierPart selection"
msgstr ""

View File

@ -27,6 +27,17 @@ class IssuePurchaseOrderForm(HelperForm):
]
class CompletePurchaseOrderForm(HelperForm):
confirm = forms.BooleanField(required=False, help_text=_("Mark order as complete"))
class Meta:
model = PurchaseOrder
fields = [
'confirm',
]
class CancelPurchaseOrderForm(HelperForm):
confirm = forms.BooleanField(required=False, help_text=_('Cancel order'))

View File

@ -188,6 +188,12 @@ class PurchaseOrder(Order):
return self.lines.filter(quantity__gt=F('received'))
@property
def is_complete(self):
""" Return True if all line items have been received """
return self.pending_line_items().count() == 0
@transaction.atomic
def receive_line_item(self, line, location, quantity, user):
""" Receive a line item (or partial line item) against this PO

View File

@ -0,0 +1,13 @@
{% extends "modal_form.html" %}
{% block pre_form_content %}
Mark this order as complete?
{% if not order.is_complete %}
<div class='alert alert-warning alert-block'>
This order has line items which have not been marked as received.
Marking this order as complete will remove these line items.
</div>
{% endif %}
{% endblock %}

View File

@ -44,6 +44,9 @@ InvenTree | {{ order }}
<button type='button' class='btn btn-default btn-glyph' id='receive-order' title='Receive items'>
<span class='glyphicon glyphicon-check'></span>
</button>
<button type='button' class='btn btn-default btn-glyph' id='complete-order' title='Mark order as complete'>
<span class='glyphicon glyphicon-ok'></span>
</button>
{% endif %}
{% if order.status == OrderStatus.PENDING or order.status == OrderStatus.PLACED %}
<button type='button' class='btn btn-default btn-glyph' id='cancel-order' title='Cancel order'>
@ -171,12 +174,14 @@ InvenTree | {{ order }}
{% block js_ready %}
{% if order.status == OrderStatus.PENDING and order.lines.count > 0 %}
$("#place-order").click(function() {
launchModalForm("{% url 'purchase-order-issue' order.id %}",
{
reload: true,
});
});
{% endif %}
$("#edit-order").click(function() {
launchModalForm("{% url 'purchase-order-edit' order.id %}",
@ -202,7 +207,15 @@ $("#po-lines-table").on('click', ".line-receive", function() {
reload: true,
data: {
line: button.attr('pk')
}
},
secondary: [
{
field: 'location',
label: 'New Location',
title: 'Create new stock location',
url: "{% url 'stock-location-create' %}",
},
]
});
});
@ -220,6 +233,12 @@ $("#receive-order").click(function() {
});
});
$("#complete-order").click(function() {
launchModalForm("{% url 'purchase-order-complete' order.id %}", {
reload: true,
});
});
$("#export-order").click(function() {
location.href = "{% url 'purchase-order-export' order.id %}";
});

View File

@ -15,6 +15,7 @@ purchase_order_detail_urls = [
url(r'^edit/?', views.PurchaseOrderEdit.as_view(), name='purchase-order-edit'),
url(r'^issue/?', views.PurchaseOrderIssue.as_view(), name='purchase-order-issue'),
url(r'^receive/?', views.PurchaseOrderReceive.as_view(), name='purchase-order-receive'),
url(r'^complete/?', views.PurchaseOrderComplete.as_view(), name='purchase-order-complete'),
url(r'^export/?', views.PurchaseOrderExport.as_view(), name='purchase-order-export'),

View File

@ -184,6 +184,42 @@ class PurchaseOrderIssue(AjaxUpdateView):
return self.renderJsonResponse(request, form, data)
class PurchaseOrderComplete(AjaxUpdateView):
""" View for marking a PurchaseOrder as complete.
"""
form_class = order_forms.CompletePurchaseOrderForm
model = PurchaseOrder
ajax_template_name = "order/order_complete.html"
ajax_form_title = "Complete Order"
context_object_name = 'order'
def get_context_data(self):
ctx = {
'order': self.get_object(),
}
return ctx
def post(self, request, *args, **kwargs):
confirm = str2bool(request.POST.get('confirm', False))
if confirm:
po = self.get_object()
po.status = OrderStatus.COMPLETE
po.save()
data = {
'form_valid': confirm
}
form = self.get_form()
return self.renderJsonResponse(request, form, data)
class PurchaseOrderExport(AjaxView):
""" File download for a purchase order

View File

@ -18,7 +18,7 @@ from django.db.models import Sum
from django.db.models import prefetch_related_objects
from django.core.validators import MinValueValidator
from django.contrib.staticfiles.templatetags.staticfiles import static
from django.conf.urls.static import static
from django.contrib.auth.models import User
from django.db.models.signals import pre_delete
from django.dispatch import receiver

View File

@ -230,7 +230,8 @@
launchModalForm("{% url 'order-parts' %}", {
data: {
part: {{ part.id }},
}
},
reload: true,
});
});

View File

@ -1,19 +1,19 @@
Django>=2.2.4 # Django package
pillow>=5.0.0 # Image manipulation
djangorestframework>=3.6.2 # DRF framework
django-cors-headers>=2.5.3 # CORS headers extension for DRF
django_filter>=1.0.2 # Extended filtering options
django-mptt>=0.10.0 # Modified Preorder Tree Traversal
Django==2.2.8 # Django package
pillow==6.2.0 # Image manipulation
djangorestframework==3.10.3 # DRF framework
django-cors-headers==3.2.0 # CORS headers extension for DRF
django_filter==2.2.0 # Extended filtering options
django-mptt==0.10.0 # Modified Preorder Tree Traversal
django-dbbackup==3.2.0 # Database backup / restore functionality
coreapi>=2.3.0 # API documentation
pygments>=2.2.0 # Syntax highlighting
tablib>=0.13.0 # Import / export data files
django-crispy-forms>=1.7.2 # Form helpers
django-import-export>=1.0.0 # Data import / export for admin interface
django-cleanup>=2.1.0 # Manage deletion of old / unused uploaded files
django-qr-code==1.0.0 # Generate QR codes
coreapi==2.3.0 # API documentation
pygments==2.2.0 # Syntax highlighting
tablib==0.13.0 # Import / export data files
django-crispy-forms==1.8.1 # Form helpers
django-import-export==2.0.0 # Data import / export for admin interface
django-cleanup==4.0.0 # Manage deletion of old / unused uploaded files
django-qr-code==1.1.0 # Generate QR codes
flake8==3.3.0 # PEP checking
coverage==4.0.3 # Unit test coverage
python-coveralls==2.9.1 # Coveralls linking (for Travis)
fuzzywuzzy>=0.17.0 # Fuzzy string matching
python-Levenshtein>=0.12.0 # Required for fuzzywuzzy
fuzzywuzzy==0.17.0 # Fuzzy string matching
python-Levenshtein==0.12.0 # Required for fuzzywuzzy