mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
Separate concept of "OrderStatus" into "SalesOrderStatus" and "PurchaseOrderStatus"
This commit is contained in:
parent
7f020cbbf6
commit
435c13cf7c
@ -18,6 +18,8 @@ function defaultFilters() {
|
||||
build: "",
|
||||
parts: "cascade=1",
|
||||
company: "",
|
||||
salesorder: "",
|
||||
purchaseorder: "",
|
||||
};
|
||||
}
|
||||
|
||||
@ -258,6 +260,8 @@ function setupFilterList(tableKey, table, target) {
|
||||
|
||||
var element = $(target);
|
||||
|
||||
console.log(tableKey + " - " + element);
|
||||
|
||||
// One blank slate, please
|
||||
element.empty();
|
||||
|
||||
@ -298,6 +302,8 @@ function setupFilterList(tableKey, table, target) {
|
||||
element.find(`#filter-tag-${tableKey}`).on('change', function() {
|
||||
var list = element.find(`#filter-value-${tableKey}`);
|
||||
|
||||
console.log('index was changed!');
|
||||
|
||||
list.replaceWith(generateFilterInput(tableKey, this.value));
|
||||
});
|
||||
|
||||
|
@ -108,13 +108,13 @@ function loadPurchaseOrderTable(table, options) {
|
||||
|
||||
options.params['supplier_detail'] = true;
|
||||
|
||||
var filters = loadTableFilters("order");
|
||||
var filters = loadTableFilters("purchaseorder");
|
||||
|
||||
for (var key in options.params) {
|
||||
filters[key] = options.params[key];
|
||||
}
|
||||
|
||||
setupFilterList("order", $(table));
|
||||
setupFilterList("purchaseorder", $(table));
|
||||
|
||||
$(table).inventreeTable({
|
||||
url: options.url,
|
||||
@ -159,7 +159,7 @@ function loadPurchaseOrderTable(table, options) {
|
||||
field: 'status',
|
||||
title: 'Status',
|
||||
formatter: function(value, row, index, field) {
|
||||
return orderStatusDisplay(row.status, row.status_text);
|
||||
return purchaseOrderStatusDisplay(row.status, row.status_text);
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -181,13 +181,13 @@ function loadSalesOrderTable(table, options) {
|
||||
options.params = options.params || {};
|
||||
options.params['customer_detail'] = true;
|
||||
|
||||
var filters = loadTableFilters("table");
|
||||
var filters = loadTableFilters("salesorder");
|
||||
|
||||
for (var key in options.params) {
|
||||
filters[key] = options.params[key];
|
||||
}
|
||||
|
||||
setupFilterList("order", $(table));
|
||||
setupFilterList("salesorder", $(table));
|
||||
|
||||
$(table).inventreeTable({
|
||||
url: options.url,
|
||||
@ -232,7 +232,7 @@ function loadSalesOrderTable(table, options) {
|
||||
field: 'status',
|
||||
title: 'Status',
|
||||
formatter: function(value, row, index, field) {
|
||||
return orderStatusDisplay(row.status, row.status_text);
|
||||
return salesOrderStatusDisplay(row.status, row.status_text);
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -70,11 +70,14 @@ class StatusCode:
|
||||
raise ValueError("Label not found")
|
||||
|
||||
|
||||
class OrderStatus(StatusCode):
|
||||
class PurchaseOrderStatus(StatusCode):
|
||||
"""
|
||||
Defines a set of status codes for a PurchaseOrder
|
||||
"""
|
||||
|
||||
# Order status codes
|
||||
PENDING = 10 # Order is pending (not yet placed)
|
||||
PLACED = 20 # Order has been placed
|
||||
PLACED = 20 # Order has been placed with supplier
|
||||
COMPLETE = 30 # Order has been completed
|
||||
CANCELLED = 40 # Order was cancelled
|
||||
LOST = 50 # Order was lost
|
||||
@ -112,6 +115,31 @@ class OrderStatus(StatusCode):
|
||||
]
|
||||
|
||||
|
||||
class SalesOrderStatus(StatusCode):
|
||||
""" Defines a set of status codes for a SalesOrder """
|
||||
|
||||
PENDING = 10 # Order is pending
|
||||
SHIPPED = 20 # Order has been shipped to customer
|
||||
CANCELLED = 40 # Order has been cancelled
|
||||
LOST = 50 # Order was lost
|
||||
RETURNED = 60 # Order was returned
|
||||
|
||||
options = {
|
||||
PENDING: _("Pending"),
|
||||
SHIPPED: _("Shipped"),
|
||||
CANCELLED: _("Cancelled"),
|
||||
LOST: _("Lost"),
|
||||
RETURNED: _("Returned"),
|
||||
}
|
||||
|
||||
labels = {
|
||||
PENDING: "primary",
|
||||
SHIPPED: "success",
|
||||
CANCELLED: "danger",
|
||||
LOST: "warning",
|
||||
RETURNED: "warning",
|
||||
}
|
||||
|
||||
class StockStatus(StatusCode):
|
||||
|
||||
OK = 10 # Item is OK
|
||||
|
@ -25,7 +25,7 @@ from stdimage.models import StdImageField
|
||||
from InvenTree.helpers import getMediaUrl, getBlankImage, getBlankThumbnail
|
||||
from InvenTree.helpers import normalize
|
||||
from InvenTree.fields import InvenTreeURLField, RoundingDecimalField
|
||||
from InvenTree.status_codes import OrderStatus
|
||||
from InvenTree.status_codes import PurchaseOrderStatus
|
||||
from common.models import Currency
|
||||
|
||||
|
||||
@ -185,11 +185,11 @@ class Company(models.Model):
|
||||
|
||||
def outstanding_purchase_orders(self):
|
||||
""" Return purchase orders which are 'outstanding' """
|
||||
return self.purchase_orders.filter(status__in=OrderStatus.OPEN)
|
||||
return self.purchase_orders.filter(status__in=PurchaseOrderStatus.OPEN)
|
||||
|
||||
def pending_purchase_orders(self):
|
||||
""" Return purchase orders which are PENDING (not yet issued) """
|
||||
return self.purchase_orders.filter(status=OrderStatus.PENDING)
|
||||
return self.purchase_orders.filter(status=PurchaseOrderStatus.PENDING)
|
||||
|
||||
def closed_purchase_orders(self):
|
||||
""" Return purchase orders which are not 'outstanding'
|
||||
@ -199,15 +199,15 @@ class Company(models.Model):
|
||||
- Returned
|
||||
"""
|
||||
|
||||
return self.purchase_orders.exclude(status__in=OrderStatus.OPEN)
|
||||
return self.purchase_orders.exclude(status__in=PurchaseOrderStatus.OPEN)
|
||||
|
||||
def complete_purchase_orders(self):
|
||||
return self.purchase_orders.filter(status=OrderStatus.COMPLETE)
|
||||
return self.purchase_orders.filter(status=PurchaseOrderStatus.COMPLETE)
|
||||
|
||||
def failed_purchase_orders(self):
|
||||
""" Return any purchase orders which were not successful """
|
||||
|
||||
return self.purchase_orders.filter(status__in=OrderStatus.FAILED)
|
||||
return self.purchase_orders.filter(status__in=PurchaseOrderStatus.FAILED)
|
||||
|
||||
|
||||
class Contact(models.Model):
|
||||
@ -384,7 +384,7 @@ class SupplierPart(models.Model):
|
||||
limited to purchase orders that are open / outstanding.
|
||||
"""
|
||||
|
||||
return self.purchase_order_line_items.prefetch_related('order').filter(order__status__in=OrderStatus.OPEN)
|
||||
return self.purchase_order_line_items.prefetch_related('order').filter(order__status__in=PurchaseOrderStatus.OPEN)
|
||||
|
||||
def on_order(self):
|
||||
""" Return the total quantity of items currently on order.
|
||||
|
@ -13,7 +13,7 @@ from django.urls import reverse
|
||||
from django.forms import HiddenInput
|
||||
|
||||
from InvenTree.views import AjaxCreateView, AjaxUpdateView, AjaxDeleteView
|
||||
from InvenTree.status_codes import OrderStatus
|
||||
from InvenTree.status_codes import PurchaseOrderStatus
|
||||
from InvenTree.helpers import str2bool
|
||||
|
||||
from common.models import Currency
|
||||
@ -137,7 +137,6 @@ class CompanyDetail(DetailView):
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
ctx = super().get_context_data(**kwargs)
|
||||
ctx['OrderStatus'] = OrderStatus
|
||||
|
||||
return ctx
|
||||
|
||||
@ -244,7 +243,6 @@ class SupplierPartDetail(DetailView):
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
ctx = super().get_context_data(**kwargs)
|
||||
ctx['OrderStatus'] = OrderStatus
|
||||
|
||||
return ctx
|
||||
|
||||
|
37
InvenTree/order/migrations/0028_auto_20200423_0956.py
Normal file
37
InvenTree/order/migrations/0028_auto_20200423_0956.py
Normal file
@ -0,0 +1,37 @@
|
||||
# Generated by Django 3.0.5 on 2020-04-23 09:56
|
||||
|
||||
import InvenTree.fields
|
||||
import django.core.validators
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('stock', '0031_auto_20200422_0209'),
|
||||
('order', '0027_auto_20200422_0236'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='purchaseorder',
|
||||
name='status',
|
||||
field=models.PositiveIntegerField(choices=[(10, 'Pending'), (20, 'Placed'), (30, 'Complete'), (40, 'Cancelled'), (50, 'Lost'), (60, 'Returned')], default=10, help_text='Purchase order status'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='salesorder',
|
||||
name='status',
|
||||
field=models.PositiveIntegerField(choices=[(10, 'Pending'), (20, 'Shipped'), (40, 'Cancelled'), (50, 'Lost'), (60, 'Returned')], default=10, help_text='Purchase order status'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='salesorderallocation',
|
||||
name='item',
|
||||
field=models.ForeignKey(help_text='Select stock item to allocate', limit_choices_to={'part__salable': True}, on_delete=django.db.models.deletion.CASCADE, related_name='sales_order_allocations', to='stock.StockItem'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='salesorderallocation',
|
||||
name='quantity',
|
||||
field=InvenTree.fields.RoundingDecimalField(decimal_places=5, default=1, help_text='Enter stock allocation quantity', max_digits=15, validators=[django.core.validators.MinValueValidator(0)]),
|
||||
),
|
||||
]
|
@ -25,7 +25,7 @@ from company.models import Company, SupplierPart
|
||||
|
||||
from InvenTree.fields import RoundingDecimalField
|
||||
from InvenTree.helpers import decimal2string, normalize
|
||||
from InvenTree.status_codes import OrderStatus
|
||||
from InvenTree.status_codes import PurchaseOrderStatus, SalesOrderStatus
|
||||
from InvenTree.models import InvenTreeAttachment
|
||||
|
||||
|
||||
@ -76,9 +76,6 @@ class Order(models.Model):
|
||||
|
||||
creation_date = models.DateField(blank=True, null=True)
|
||||
|
||||
status = models.PositiveIntegerField(default=OrderStatus.PENDING, choices=OrderStatus.items(),
|
||||
help_text='Order status')
|
||||
|
||||
created_by = models.ForeignKey(User,
|
||||
on_delete=models.SET_NULL,
|
||||
blank=True, null=True,
|
||||
@ -91,29 +88,6 @@ class Order(models.Model):
|
||||
|
||||
notes = MarkdownxField(blank=True, help_text=_('Order notes'))
|
||||
|
||||
def place_order(self):
|
||||
""" Marks the order as PLACED. Order must be currently PENDING. """
|
||||
|
||||
if self.status == OrderStatus.PENDING:
|
||||
self.status = OrderStatus.PLACED
|
||||
self.issue_date = datetime.now().date()
|
||||
self.save()
|
||||
|
||||
def complete_order(self):
|
||||
""" Marks the order as COMPLETE. Order must be currently PLACED. """
|
||||
|
||||
if self.status == OrderStatus.PLACED:
|
||||
self.status = OrderStatus.COMPLETE
|
||||
self.complete_date = datetime.now().date()
|
||||
self.save()
|
||||
|
||||
def cancel_order(self):
|
||||
""" Marks the order as CANCELLED. """
|
||||
|
||||
if self.status in [OrderStatus.PLACED, OrderStatus.PENDING]:
|
||||
self.status = OrderStatus.CANCELLED
|
||||
self.save()
|
||||
|
||||
|
||||
class PurchaseOrder(Order):
|
||||
""" A PurchaseOrder represents goods shipped inwards from an external supplier.
|
||||
@ -129,6 +103,9 @@ class PurchaseOrder(Order):
|
||||
def __str__(self):
|
||||
return "PO {ref} - {company}".format(ref=self.reference, company=self.supplier.name)
|
||||
|
||||
status = models.PositiveIntegerField(default=PurchaseOrderStatus.PENDING, choices=PurchaseOrderStatus.items(),
|
||||
help_text='Purchase order status')
|
||||
|
||||
supplier = models.ForeignKey(
|
||||
Company, on_delete=models.CASCADE,
|
||||
limit_choices_to={
|
||||
@ -195,6 +172,29 @@ class PurchaseOrder(Order):
|
||||
|
||||
line.save()
|
||||
|
||||
def place_order(self):
|
||||
""" Marks the PurchaseOrder as PLACED. Order must be currently PENDING. """
|
||||
|
||||
if self.status == PurchaseOrderStatus.PENDING:
|
||||
self.status = PurchaseOrderStatus.PLACED
|
||||
self.issue_date = datetime.now().date()
|
||||
self.save()
|
||||
|
||||
def complete_order(self):
|
||||
""" Marks the PurchaseOrder as COMPLETE. Order must be currently PLACED. """
|
||||
|
||||
if self.status == PurchaseOrderStatus.PLACED:
|
||||
self.status = PurchaseOrderStatus.COMPLETE
|
||||
self.complete_date = datetime.now().date()
|
||||
self.save()
|
||||
|
||||
def cancel_order(self):
|
||||
""" Marks the PurchaseOrder as CANCELLED. """
|
||||
|
||||
if self.status in [PurchaseOrderStatus.PLACED, PurchaseOrderStatus.PENDING]:
|
||||
self.status = PurchaseOrderStatus.CANCELLED
|
||||
self.save()
|
||||
|
||||
def pending_line_items(self):
|
||||
""" Return a list of pending line items for this order.
|
||||
Any line item where 'received' < 'quantity' will be returned.
|
||||
@ -213,7 +213,7 @@ class PurchaseOrder(Order):
|
||||
""" Receive a line item (or partial line item) against this PO
|
||||
"""
|
||||
|
||||
if not self.status == OrderStatus.PLACED:
|
||||
if not self.status == PurchaseOrderStatus.PLACED:
|
||||
raise ValidationError({"status": _("Lines can only be received against an order marked as 'Placed'")})
|
||||
|
||||
try:
|
||||
@ -275,6 +275,9 @@ class SalesOrder(Order):
|
||||
help_text=_("Customer"),
|
||||
)
|
||||
|
||||
status = models.PositiveIntegerField(default=SalesOrderStatus.PENDING, choices=SalesOrderStatus.items(),
|
||||
help_text='Purchase order status')
|
||||
|
||||
customer_reference = models.CharField(max_length=64, blank=True, help_text=_("Customer order reference code"))
|
||||
|
||||
def is_fully_allocated(self):
|
||||
|
@ -67,7 +67,7 @@ src="{% static 'img/blank_image.png' %}"
|
||||
<tr>
|
||||
<td><span class='fas fa-info'></span></td>
|
||||
<td>{% trans "Order Status" %}</td>
|
||||
<td>{% order_status order.status %}</td>
|
||||
<td>{% purchase_order_status order.status %}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><span class='fas fa-building'></span></td>
|
||||
|
@ -15,7 +15,7 @@ InvenTree | {% trans "Purchase Orders" %}
|
||||
<div id='table-buttons'>
|
||||
<div class='button-toolbar container-fluid' style='float: right;'>
|
||||
<button class='btn btn-primary' type='button' id='po-create' title='{% trans "Create new purchase order" %}'>{% trans "New Purchase Order" %}</button>
|
||||
<div class='filter-list' id='filter-list-order'>
|
||||
<div class='filter-list' id='filter-list-purchaseorder'>
|
||||
<!-- An empty div in which the filter list will be constructed -->
|
||||
</div>
|
||||
</div>
|
||||
|
@ -56,7 +56,7 @@ src="{% static 'img/blank_image.png' %}"
|
||||
<tr>
|
||||
<td><span class='fas fa-info'></span></td>
|
||||
<td>{% trans "Order Status" %}</td>
|
||||
<td>{% order_status order.status %}</td>
|
||||
<td>{% sales_order_status order.status %}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><span class='fas fa-building'></span></td>
|
||||
|
@ -15,7 +15,7 @@ InvenTree | {% trans "Sales Orders" %}
|
||||
<div id='table-buttons'>
|
||||
<div class='button-toolbar container-fluid' style='float: right;'>
|
||||
<button class='btn btn-primary' type='button' id='so-create' title='{% trans "Create new sales order" %}'>{% trans "New Sales Order" %}</button>
|
||||
<div class='filter-list' id='filter-list-order'>
|
||||
<div class='filter-list' id='filter-list-salesorder'>
|
||||
<!-- An empty div in which the filter list will be constructed -->
|
||||
</div>
|
||||
</div>
|
||||
|
@ -7,7 +7,7 @@ from django.test import TestCase
|
||||
from django.urls import reverse
|
||||
from django.contrib.auth import get_user_model
|
||||
|
||||
from InvenTree.status_codes import OrderStatus
|
||||
from InvenTree.status_codes import PurchaseOrderStatus
|
||||
|
||||
from .models import PurchaseOrder, PurchaseOrderLineItem
|
||||
|
||||
@ -53,7 +53,7 @@ class POTests(OrderViewTestCase):
|
||||
response = self.client.get(reverse('po-detail', args=(1,)))
|
||||
self.assertEqual(response.status_code, 200)
|
||||
keys = response.context.keys()
|
||||
self.assertIn('OrderStatus', keys)
|
||||
self.assertIn('PurchaseOrderStatus', keys)
|
||||
|
||||
def test_po_create(self):
|
||||
""" Launch forms to create new PurchaseOrder"""
|
||||
@ -91,7 +91,7 @@ class POTests(OrderViewTestCase):
|
||||
url = reverse('po-issue', args=(1,))
|
||||
|
||||
order = PurchaseOrder.objects.get(pk=1)
|
||||
self.assertEqual(order.status, OrderStatus.PENDING)
|
||||
self.assertEqual(order.status, PurchaseOrderStatus.PENDING)
|
||||
|
||||
# Test without confirmation
|
||||
response = self.client.post(url, {'confirm': 0}, HTTP_X_REQUESTED_WITH='XMLHttpRequest')
|
||||
@ -109,7 +109,7 @@ class POTests(OrderViewTestCase):
|
||||
|
||||
# Test that the order was actually placed
|
||||
order = PurchaseOrder.objects.get(pk=1)
|
||||
self.assertEqual(order.status, OrderStatus.PLACED)
|
||||
self.assertEqual(order.status, PurchaseOrderStatus.PLACED)
|
||||
|
||||
def test_line_item_create(self):
|
||||
""" Test the form for adding a new LineItem to a PurchaseOrder """
|
||||
@ -117,7 +117,7 @@ class POTests(OrderViewTestCase):
|
||||
# Record the number of line items in the PurchaseOrder
|
||||
po = PurchaseOrder.objects.get(pk=1)
|
||||
n = po.lines.count()
|
||||
self.assertEqual(po.status, OrderStatus.PENDING)
|
||||
self.assertEqual(po.status, PurchaseOrderStatus.PENDING)
|
||||
|
||||
url = reverse('po-line-item-create')
|
||||
|
||||
@ -181,7 +181,7 @@ class TestPOReceive(OrderViewTestCase):
|
||||
super().setUp()
|
||||
|
||||
self.po = PurchaseOrder.objects.get(pk=1)
|
||||
self.po.status = OrderStatus.PLACED
|
||||
self.po.status = PurchaseOrderStatus.PLACED
|
||||
self.po.save()
|
||||
self.url = reverse('po-receive', args=(1,))
|
||||
|
||||
|
@ -6,7 +6,7 @@ from .models import PurchaseOrder, PurchaseOrderLineItem
|
||||
from stock.models import StockLocation
|
||||
from company.models import SupplierPart
|
||||
|
||||
from InvenTree.status_codes import OrderStatus
|
||||
from InvenTree.status_codes import PurchaseOrderStatus
|
||||
|
||||
|
||||
class OrderTest(TestCase):
|
||||
@ -57,7 +57,7 @@ class OrderTest(TestCase):
|
||||
|
||||
order = PurchaseOrder.objects.get(pk=1)
|
||||
|
||||
self.assertEqual(order.status, OrderStatus.PENDING)
|
||||
self.assertEqual(order.status, PurchaseOrderStatus.PENDING)
|
||||
self.assertEqual(order.lines.count(), 3)
|
||||
|
||||
sku = SupplierPart.objects.get(SKU='ACME-WIDGET')
|
||||
@ -104,14 +104,14 @@ class OrderTest(TestCase):
|
||||
self.assertEqual(len(order.pending_line_items()), 3)
|
||||
|
||||
# Should fail, as order is 'PENDING' not 'PLACED"
|
||||
self.assertEqual(order.status, OrderStatus.PENDING)
|
||||
self.assertEqual(order.status, PurchaseOrderStatus.PENDING)
|
||||
|
||||
with self.assertRaises(django_exceptions.ValidationError):
|
||||
order.receive_line_item(line, loc, 50, user=None)
|
||||
|
||||
order.place_order()
|
||||
|
||||
self.assertEqual(order.status, OrderStatus.PLACED)
|
||||
self.assertEqual(order.status, PurchaseOrderStatus.PLACED)
|
||||
|
||||
order.receive_line_item(line, loc, 50, user=None)
|
||||
|
||||
@ -134,9 +134,9 @@ class OrderTest(TestCase):
|
||||
order.receive_line_item(line, loc, 500, user=None)
|
||||
|
||||
self.assertEqual(part.on_order, 800)
|
||||
self.assertEqual(order.status, OrderStatus.PLACED)
|
||||
self.assertEqual(order.status, PurchaseOrderStatus.PLACED)
|
||||
|
||||
for line in order.pending_line_items():
|
||||
order.receive_line_item(line, loc, line.quantity, user=None)
|
||||
|
||||
self.assertEqual(order.status, OrderStatus.COMPLETE)
|
||||
self.assertEqual(order.status, PurchaseOrderStatus.COMPLETE)
|
||||
|
@ -29,7 +29,7 @@ from . import forms as order_forms
|
||||
from InvenTree.views import AjaxView, AjaxCreateView, AjaxUpdateView, AjaxDeleteView
|
||||
from InvenTree.helpers import DownloadFile, str2bool
|
||||
|
||||
from InvenTree.status_codes import OrderStatus
|
||||
from InvenTree.status_codes import PurchaseOrderStatus
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@ -52,8 +52,6 @@ class PurchaseOrderIndex(ListView):
|
||||
def get_context_data(self, **kwargs):
|
||||
ctx = super().get_context_data(**kwargs)
|
||||
|
||||
ctx['OrderStatus'] = OrderStatus
|
||||
|
||||
return ctx
|
||||
|
||||
|
||||
@ -74,8 +72,6 @@ class PurchaseOrderDetail(DetailView):
|
||||
def get_context_data(self, **kwargs):
|
||||
ctx = super().get_context_data(**kwargs)
|
||||
|
||||
ctx['OrderStatus'] = OrderStatus
|
||||
|
||||
return ctx
|
||||
|
||||
|
||||
@ -280,7 +276,7 @@ class PurchaseOrderCreate(AjaxCreateView):
|
||||
def get_initial(self):
|
||||
initials = super().get_initial().copy()
|
||||
|
||||
initials['status'] = OrderStatus.PENDING
|
||||
initials['status'] = PurchaseOrderStatus.PENDING
|
||||
|
||||
supplier_id = self.request.GET.get('supplier', None)
|
||||
|
||||
@ -310,7 +306,7 @@ class SalesOrderCreate(AjaxCreateView):
|
||||
def get_initial(self):
|
||||
initials = super().get_initial().copy()
|
||||
|
||||
initials['status'] = OrderStatus.PENDING
|
||||
initials['status'] = PurchaseOrderStatus.PENDING
|
||||
|
||||
customer_id = self.request.GET.get('customer', None)
|
||||
|
||||
@ -343,7 +339,7 @@ class PurchaseOrderEdit(AjaxUpdateView):
|
||||
order = self.get_object()
|
||||
|
||||
# Prevent user from editing supplier if there are already lines in the order
|
||||
if order.lines.count() > 0 or not order.status == OrderStatus.PENDING:
|
||||
if order.lines.count() > 0 or not order.status == PurchaseOrderStatus.PENDING:
|
||||
form.fields['supplier'].widget = HiddenInput()
|
||||
|
||||
return form
|
||||
@ -455,7 +451,7 @@ class PurchaseOrderComplete(AjaxUpdateView):
|
||||
|
||||
if confirm:
|
||||
po = self.get_object()
|
||||
po.status = OrderStatus.COMPLETE
|
||||
po.status = PurchaseOrderStatus.COMPLETE
|
||||
po.save()
|
||||
|
||||
data = {
|
||||
@ -1024,7 +1020,7 @@ class POLineItemCreate(AjaxCreateView):
|
||||
|
||||
# Limit the available to orders to ones that are PENDING
|
||||
query = form.fields['order'].queryset
|
||||
query = query.filter(status=OrderStatus.PENDING)
|
||||
query = query.filter(status=PurchaseOrderStatus.PENDING)
|
||||
form.fields['order'].queryset = query
|
||||
|
||||
order_id = form['order'].value()
|
||||
|
@ -39,7 +39,7 @@ from InvenTree.models import InvenTreeTree, InvenTreeAttachment
|
||||
from InvenTree.fields import InvenTreeURLField
|
||||
from InvenTree.helpers import decimal2string, normalize
|
||||
|
||||
from InvenTree.status_codes import BuildStatus, StockStatus, OrderStatus
|
||||
from InvenTree.status_codes import BuildStatus, StockStatus, PurchaseOrderStatus
|
||||
|
||||
from company.models import SupplierPart
|
||||
|
||||
@ -955,18 +955,18 @@ class Part(models.Model):
|
||||
def open_purchase_orders(self):
|
||||
""" Return a list of open purchase orders against this part """
|
||||
|
||||
return [order for order in self.purchase_orders() if order.status in OrderStatus.OPEN]
|
||||
return [order for order in self.purchase_orders() if order.status in PurchaseOrderStatus.OPEN]
|
||||
|
||||
def closed_purchase_orders(self):
|
||||
""" Return a list of closed purchase orders against this part """
|
||||
|
||||
return [order for order in self.purchase_orders() if order.status not in OrderStatus.OPEN]
|
||||
return [order for order in self.purchase_orders() if order.status not in PurchaseOrderStatus.OPEN]
|
||||
|
||||
@property
|
||||
def on_order(self):
|
||||
""" Return the total number of items on order for this part. """
|
||||
|
||||
orders = self.supplier_parts.filter(purchase_order_line_items__order__status__in=OrderStatus.OPEN).aggregate(
|
||||
orders = self.supplier_parts.filter(purchase_order_line_items__order__status__in=PurchaseOrderStatus.OPEN).aggregate(
|
||||
quantity=Sum('purchase_order_line_items__quantity'),
|
||||
received=Sum('purchase_order_line_items__received')
|
||||
)
|
||||
|
@ -15,7 +15,7 @@ from decimal import Decimal
|
||||
from django.db.models import Q, Sum
|
||||
from django.db.models.functions import Coalesce
|
||||
|
||||
from InvenTree.status_codes import StockStatus, OrderStatus, BuildStatus
|
||||
from InvenTree.status_codes import StockStatus, PurchaseOrderStatus, BuildStatus
|
||||
from InvenTree.serializers import InvenTreeModelSerializer
|
||||
|
||||
|
||||
@ -120,7 +120,7 @@ class PartSerializer(InvenTreeModelSerializer):
|
||||
stock_filter = Q(stock_items__status__in=StockStatus.AVAILABLE_CODES)
|
||||
|
||||
# Filter to limit orders to "open"
|
||||
order_filter = Q(supplier_parts__purchase_order_line_items__order__status__in=OrderStatus.OPEN)
|
||||
order_filter = Q(supplier_parts__purchase_order_line_items__order__status__in=PurchaseOrderStatus.OPEN)
|
||||
|
||||
# Filter to limit builds to "active"
|
||||
build_filter = Q(builds__status__in=BuildStatus.ACTIVE_CODES)
|
||||
|
@ -4,14 +4,20 @@ Provide templates for the various model status codes.
|
||||
|
||||
from django import template
|
||||
from django.utils.safestring import mark_safe
|
||||
from InvenTree.status_codes import OrderStatus, StockStatus, BuildStatus
|
||||
from InvenTree.status_codes import PurchaseOrderStatus, SalesOrderStatus
|
||||
from InvenTree.status_codes import StockStatus, BuildStatus
|
||||
|
||||
register = template.Library()
|
||||
|
||||
|
||||
@register.simple_tag
|
||||
def order_status(key, *args, **kwargs):
|
||||
return mark_safe(OrderStatus.render(key))
|
||||
def purchase_order_status(key, *args, **kwargs):
|
||||
return mark_safe(PurchaseOrderStatus.render(key))
|
||||
|
||||
|
||||
@register.simple_tag
|
||||
def sales_order_status(key, *args, **kwargs):
|
||||
return mark_safe(SalesOrderStatus.render(key))
|
||||
|
||||
|
||||
@register.simple_tag
|
||||
@ -30,7 +36,8 @@ def load_status_codes(context):
|
||||
Make the various StatusCodes available to the page context
|
||||
"""
|
||||
|
||||
context['order_status_codes'] = OrderStatus.list()
|
||||
context['purchase_order_status_codes'] = PurchaseOrderStatus.list()
|
||||
context['sales_order_status_codes'] = SalesOrderStatus.list()
|
||||
context['stock_status_codes'] = StockStatus.list()
|
||||
context['build_status_codes'] = BuildStatus.list()
|
||||
|
||||
|
@ -38,7 +38,7 @@ from InvenTree.views import AjaxView, AjaxCreateView, AjaxUpdateView, AjaxDelete
|
||||
from InvenTree.views import QRCodeView
|
||||
|
||||
from InvenTree.helpers import DownloadFile, str2bool
|
||||
from InvenTree.status_codes import OrderStatus, BuildStatus
|
||||
from InvenTree.status_codes import PurchaseOrderStatus, BuildStatus
|
||||
|
||||
|
||||
class PartIndex(ListView):
|
||||
@ -561,8 +561,6 @@ class PartNotes(UpdateView):
|
||||
ctx['starred'] = part.isStarredBy(self.request.user)
|
||||
ctx['disabled'] = not part.active
|
||||
|
||||
ctx['OrderStatus'] = OrderStatus
|
||||
|
||||
return ctx
|
||||
|
||||
|
||||
@ -593,9 +591,6 @@ class PartDetail(DetailView):
|
||||
context['starred'] = part.isStarredBy(self.request.user)
|
||||
context['disabled'] = not part.active
|
||||
|
||||
context['OrderStatus'] = OrderStatus
|
||||
context['BuildStatus'] = BuildStatus
|
||||
|
||||
return context
|
||||
|
||||
|
||||
|
@ -7,7 +7,8 @@
|
||||
|
||||
{% include "status_codes.html" with label='stock' options=stock_status_codes %}
|
||||
{% include "status_codes.html" with label='build' options=build_status_codes %}
|
||||
{% include "status_codes.html" with label='order' options=order_status_codes %}
|
||||
{% include "status_codes.html" with label='purchaseOrder' options=purchase_order_status_codes %}
|
||||
{% include "status_codes.html" with label='salesOrder' options=sales_order_status_codes %}
|
||||
|
||||
|
||||
function getAvailableTableFilters(tableKey) {
|
||||
@ -52,11 +53,20 @@ function getAvailableTableFilters(tableKey) {
|
||||
}
|
||||
|
||||
// Filters for the "Order" table
|
||||
if (tableKey == "order") {
|
||||
if (tableKey == "purchaseorder") {
|
||||
return {
|
||||
status: {
|
||||
title: '{% trans "Order status" %}',
|
||||
options: orderCodes,
|
||||
options: purchaseOrderCodes,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
if (tableKey == "salesorder") {
|
||||
return {
|
||||
status: {
|
||||
title: '{% trans "Order status" %}',
|
||||
options: salesOrderCodes,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user