mirror of
https://github.com/inventree/InvenTree.git
synced 2025-06-18 04:55:44 +00:00
Refactor states/status (#4857)
* add file for states * move general definition out * add some tests and docs * add tests for invalid definitions * make status_label tag generic * move templatetags * remove unused tag * rename test file * make status label a lookup * rename tags * move import structure * add missing tag * collect states dynamically * fix context function * move api function out * add tests for tags * rename tests * refactor imports * Add test for API function * improve errors and add tests for imporved errors * make test calls simpler * refactor definitions to use enums * switch to enum * refactor definitions to use enums * fix lookup * fix tag name * make _TAG lookup a function * cleanup BaseEnum * make _TAG definition simpler * restructure status codes to enum * reduce LoC * type status codes as int * add specific function for template context * Add definition for lookups * fix filter lookup * TEST: "fix" action lookup * Add missing migrations * Make all group code references explict * change default on models to value * switch to IntEnum * move groups into a seperate class * only request _TAG if it exsists * use value and list * use dedicated groups * fix stock assigment * fix order code * more fixes * fix borked change * fix render lookup * add group * fix import * fix syntax * clenup * fix migrations * fix typo * fix wrong value usage * fix test * remove group section * remove group section * add more test cases * Add more docstring * move choices out of migrations * change import ordeR? * last try before I revert * Update part.migrations.0112 - Add custom migration class which handles errors * Add unit test for migration - Ensure that the new fields are added to the model * Update reference to PR --------- Co-authored-by: Oliver Walters <oliver.henry.walters@gmail.com>
This commit is contained in:
@ -29,8 +29,9 @@ from InvenTree.mixins import (CreateAPI, CustomRetrieveUpdateDestroyAPI,
|
||||
RetrieveUpdateAPI, RetrieveUpdateDestroyAPI,
|
||||
UpdateAPI)
|
||||
from InvenTree.permissions import RolePermission
|
||||
from InvenTree.status_codes import (BuildStatus, PurchaseOrderStatus,
|
||||
SalesOrderStatus)
|
||||
from InvenTree.status_codes import (BuildStatusGroups,
|
||||
PurchaseOrderStatusGroups,
|
||||
SalesOrderStatusGroups)
|
||||
from part.admin import PartCategoryResource, PartResource
|
||||
|
||||
from . import serializers as part_serializers
|
||||
@ -479,7 +480,7 @@ class PartScheduling(RetrieveAPI):
|
||||
# Add purchase order (incoming stock) information
|
||||
po_lines = order.models.PurchaseOrderLineItem.objects.filter(
|
||||
part__part=part,
|
||||
order__status__in=PurchaseOrderStatus.OPEN,
|
||||
order__status__in=PurchaseOrderStatusGroups.OPEN,
|
||||
)
|
||||
|
||||
for line in po_lines:
|
||||
@ -502,7 +503,7 @@ class PartScheduling(RetrieveAPI):
|
||||
# Add sales order (outgoing stock) information
|
||||
so_lines = order.models.SalesOrderLineItem.objects.filter(
|
||||
part=part,
|
||||
order__status__in=SalesOrderStatus.OPEN,
|
||||
order__status__in=SalesOrderStatusGroups.OPEN,
|
||||
)
|
||||
|
||||
for line in so_lines:
|
||||
@ -522,7 +523,7 @@ class PartScheduling(RetrieveAPI):
|
||||
# Add build orders (incoming stock) information
|
||||
build_orders = Build.objects.filter(
|
||||
part=part,
|
||||
status__in=BuildStatus.ACTIVE_CODES
|
||||
status__in=BuildStatusGroups.ACTIVE_CODES
|
||||
)
|
||||
|
||||
for build in build_orders:
|
||||
@ -567,12 +568,12 @@ class PartScheduling(RetrieveAPI):
|
||||
# An "inherited" BOM item filters down to variant parts also
|
||||
children = bom_item.part.get_descendants(include_self=True)
|
||||
builds = Build.objects.filter(
|
||||
status__in=BuildStatus.ACTIVE_CODES,
|
||||
status__in=BuildStatusGroups.ACTIVE_CODES,
|
||||
part__in=children,
|
||||
)
|
||||
else:
|
||||
builds = Build.objects.filter(
|
||||
status__in=BuildStatus.ACTIVE_CODES,
|
||||
status__in=BuildStatusGroups.ACTIVE_CODES,
|
||||
part=bom_item.part,
|
||||
)
|
||||
|
||||
@ -1197,7 +1198,7 @@ class PartList(PartMixin, APIDownloadMixin, ListCreateAPI):
|
||||
|
||||
if stock_to_build is not None:
|
||||
# Get active builds
|
||||
builds = Build.objects.filter(status__in=BuildStatus.ACTIVE_CODES)
|
||||
builds = Build.objects.filter(status__in=BuildStatusGroups.ACTIVE_CODES)
|
||||
# Store parts with builds needing stock
|
||||
parts_needed_to_complete_builds = []
|
||||
# Filter required parts
|
||||
|
@ -28,8 +28,9 @@ from sql_util.utils import SubquerySum
|
||||
|
||||
import part.models
|
||||
import stock.models
|
||||
from InvenTree.status_codes import (BuildStatus, PurchaseOrderStatus,
|
||||
SalesOrderStatus)
|
||||
from InvenTree.status_codes import (BuildStatusGroups,
|
||||
PurchaseOrderStatusGroups,
|
||||
SalesOrderStatusGroups)
|
||||
|
||||
|
||||
def annotate_on_order_quantity(reference: str = ''):
|
||||
@ -46,7 +47,7 @@ def annotate_on_order_quantity(reference: str = ''):
|
||||
# Filter only 'active' purhase orders
|
||||
# Filter only line with outstanding quantity
|
||||
order_filter = Q(
|
||||
order__status__in=PurchaseOrderStatus.OPEN,
|
||||
order__status__in=PurchaseOrderStatusGroups.OPEN,
|
||||
quantity__gt=F('received'),
|
||||
)
|
||||
|
||||
@ -111,7 +112,7 @@ def annotate_build_order_allocations(reference: str = ''):
|
||||
"""
|
||||
|
||||
# Build filter only returns 'active' build orders
|
||||
build_filter = Q(build__status__in=BuildStatus.ACTIVE_CODES)
|
||||
build_filter = Q(build__status__in=BuildStatusGroups.ACTIVE_CODES)
|
||||
|
||||
return Coalesce(
|
||||
SubquerySum(
|
||||
@ -137,7 +138,7 @@ def annotate_sales_order_allocations(reference: str = ''):
|
||||
|
||||
# Order filter only returns incomplete shipments for open orders
|
||||
order_filter = Q(
|
||||
line__order__status__in=SalesOrderStatus.OPEN,
|
||||
line__order__status__in=SalesOrderStatusGroups.OPEN,
|
||||
shipment__shipment_date=None,
|
||||
)
|
||||
|
||||
|
@ -51,8 +51,9 @@ from InvenTree.helpers import (decimal2money, decimal2string, normalize,
|
||||
from InvenTree.models import (DataImportMixin, InvenTreeAttachment,
|
||||
InvenTreeBarcodeMixin, InvenTreeNotesMixin,
|
||||
InvenTreeTree, MetadataMixin)
|
||||
from InvenTree.status_codes import (BuildStatus, PurchaseOrderStatus,
|
||||
SalesOrderStatus)
|
||||
from InvenTree.status_codes import (BuildStatusGroups, PurchaseOrderStatus,
|
||||
PurchaseOrderStatusGroups,
|
||||
SalesOrderStatus, SalesOrderStatusGroups)
|
||||
from order import models as OrderModels
|
||||
from stock import models as StockModels
|
||||
|
||||
@ -1070,7 +1071,7 @@ class Part(InvenTreeBarcodeMixin, InvenTreeNotesMixin, MetadataMixin, MPTTModel)
|
||||
# Now, get a list of outstanding build orders which require this part
|
||||
builds = BuildModels.Build.objects.filter(
|
||||
part__in=self.get_used_in(),
|
||||
status__in=BuildStatus.ACTIVE_CODES
|
||||
status__in=BuildStatusGroups.ACTIVE_CODES
|
||||
)
|
||||
|
||||
return builds
|
||||
@ -1104,7 +1105,7 @@ class Part(InvenTreeBarcodeMixin, InvenTreeNotesMixin, MetadataMixin, MPTTModel)
|
||||
|
||||
# Get a list of line items for open orders which match this part
|
||||
open_lines = OrderModels.SalesOrderLineItem.objects.filter(
|
||||
order__status__in=SalesOrderStatus.OPEN,
|
||||
order__status__in=SalesOrderStatusGroups.OPEN,
|
||||
part=self
|
||||
)
|
||||
|
||||
@ -1117,7 +1118,7 @@ class Part(InvenTreeBarcodeMixin, InvenTreeNotesMixin, MetadataMixin, MPTTModel)
|
||||
"""Return the quantity of this part required for active sales orders."""
|
||||
# Get a list of line items for open orders which match this part
|
||||
open_lines = OrderModels.SalesOrderLineItem.objects.filter(
|
||||
order__status__in=SalesOrderStatus.OPEN,
|
||||
order__status__in=SalesOrderStatusGroups.OPEN,
|
||||
part=self
|
||||
)
|
||||
|
||||
@ -1329,7 +1330,7 @@ class Part(InvenTreeBarcodeMixin, InvenTreeNotesMixin, MetadataMixin, MPTTModel)
|
||||
|
||||
Builds marked as 'complete' or 'cancelled' are ignored
|
||||
"""
|
||||
return self.builds.filter(status__in=BuildStatus.ACTIVE_CODES)
|
||||
return self.builds.filter(status__in=BuildStatusGroups.ACTIVE_CODES)
|
||||
|
||||
@property
|
||||
def quantity_being_built(self):
|
||||
@ -1401,13 +1402,13 @@ class Part(InvenTreeBarcodeMixin, InvenTreeNotesMixin, MetadataMixin, MPTTModel)
|
||||
if pending is True:
|
||||
# Look only for 'open' orders which have not shipped
|
||||
queryset = queryset.filter(
|
||||
line__order__status__in=SalesOrderStatus.OPEN,
|
||||
line__order__status__in=SalesOrderStatusGroups.OPEN,
|
||||
shipment__shipment_date=None,
|
||||
)
|
||||
elif pending is False:
|
||||
# Look only for 'closed' orders or orders which have shipped
|
||||
queryset = queryset.exclude(
|
||||
line__order__status__in=SalesOrderStatus.OPEN,
|
||||
line__order__status__in=SalesOrderStatusGroups.OPEN,
|
||||
shipment__shipment_date=None,
|
||||
)
|
||||
|
||||
@ -2161,7 +2162,7 @@ class Part(InvenTreeBarcodeMixin, InvenTreeNotesMixin, MetadataMixin, MPTTModel)
|
||||
|
||||
# Look at any incomplete line item for open orders
|
||||
lines = sp.purchase_order_line_items.filter(
|
||||
order__status__in=PurchaseOrderStatus.OPEN,
|
||||
order__status__in=PurchaseOrderStatusGroups.OPEN,
|
||||
quantity__gt=F('received'),
|
||||
)
|
||||
|
||||
@ -2559,7 +2560,7 @@ class PartPricing(common.models.MetaMixin):
|
||||
|
||||
# Find all line items for completed orders which reference this part
|
||||
line_items = OrderModels.PurchaseOrderLineItem.objects.filter(
|
||||
order__status=PurchaseOrderStatus.COMPLETE,
|
||||
order__status=PurchaseOrderStatus.COMPLETE.value,
|
||||
received__gt=0,
|
||||
part__part=self.part,
|
||||
)
|
||||
|
@ -25,7 +25,7 @@ import InvenTree.status
|
||||
import part.filters
|
||||
import part.tasks
|
||||
import stock.models
|
||||
from InvenTree.status_codes import BuildStatus
|
||||
from InvenTree.status_codes import BuildStatusGroups
|
||||
from InvenTree.tasks import offload_task
|
||||
|
||||
from .models import (BomItem, BomItemSubstitute, Part, PartAttachment,
|
||||
@ -532,7 +532,7 @@ class PartSerializer(InvenTree.serializers.RemoteImageMixin, InvenTree.serialize
|
||||
|
||||
# Filter to limit builds to "active"
|
||||
build_filter = Q(
|
||||
status__in=BuildStatus.ACTIVE_CODES
|
||||
status__in=BuildStatusGroups.ACTIVE_CODES
|
||||
)
|
||||
|
||||
# Annotate with the total 'building' quantity
|
||||
|
@ -1,46 +0,0 @@
|
||||
"""Provide templates for the various model status codes."""
|
||||
|
||||
from django import template
|
||||
from django.utils.safestring import mark_safe
|
||||
|
||||
from InvenTree.status_codes import (BuildStatus, PurchaseOrderStatus,
|
||||
ReturnOrderStatus, SalesOrderStatus,
|
||||
StockStatus)
|
||||
|
||||
register = template.Library()
|
||||
|
||||
|
||||
@register.simple_tag
|
||||
def purchase_order_status_label(key, *args, **kwargs):
|
||||
"""Render a PurchaseOrder status label."""
|
||||
return mark_safe(PurchaseOrderStatus.render(key, large=kwargs.get('large', False)))
|
||||
|
||||
|
||||
@register.simple_tag
|
||||
def sales_order_status_label(key, *args, **kwargs):
|
||||
"""Render a SalesOrder status label."""
|
||||
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
|
||||
def stock_status_label(key, *args, **kwargs):
|
||||
"""Render a StockItem status label."""
|
||||
return mark_safe(StockStatus.render(key, large=kwargs.get('large', False)))
|
||||
|
||||
|
||||
@register.simple_tag
|
||||
def stock_status_text(key, *args, **kwargs):
|
||||
"""Render the text value of a StockItem status value"""
|
||||
return mark_safe(StockStatus.text(key))
|
||||
|
||||
|
||||
@register.simple_tag
|
||||
def build_status_label(key, *args, **kwargs):
|
||||
"""Render a Build status label."""
|
||||
return mark_safe(BuildStatus.render(key, large=kwargs.get('large', False)))
|
@ -18,7 +18,7 @@ import company.models
|
||||
import order.models
|
||||
from common.models import InvenTreeSetting
|
||||
from company.models import Company, SupplierPart
|
||||
from InvenTree.status_codes import (BuildStatus, PurchaseOrderStatus,
|
||||
from InvenTree.status_codes import (BuildStatus, PurchaseOrderStatusGroups,
|
||||
StockStatus)
|
||||
from InvenTree.unit_test import InvenTreeAPITestCase
|
||||
from part.models import (BomItem, BomItemSubstitute, Part, PartCategory,
|
||||
@ -1628,7 +1628,7 @@ class PartDetailTests(PartAPITestBase):
|
||||
# How many parts are 'on order' for this part?
|
||||
lines = order.models.PurchaseOrderLineItem.objects.filter(
|
||||
part__part__pk=1,
|
||||
order__status__in=PurchaseOrderStatus.OPEN,
|
||||
order__status__in=PurchaseOrderStatusGroups.OPEN,
|
||||
)
|
||||
|
||||
on_order = 0
|
||||
@ -1857,7 +1857,7 @@ class PartAPIAggregationTest(InvenTreeAPITestCase):
|
||||
StockItem.objects.create(part=cls.part, quantity=300)
|
||||
|
||||
# Now create another 400 units which are LOST
|
||||
StockItem.objects.create(part=cls.part, quantity=400, status=StockStatus.LOST)
|
||||
StockItem.objects.create(part=cls.part, quantity=400, status=StockStatus.LOST.value)
|
||||
|
||||
def get_part_data(self):
|
||||
"""Helper function for retrieving part data"""
|
||||
@ -1992,7 +1992,7 @@ class PartAPIAggregationTest(InvenTreeAPITestCase):
|
||||
quantity=10,
|
||||
title='Making some assemblies',
|
||||
reference='BO-9999',
|
||||
status=BuildStatus.PRODUCTION,
|
||||
status=BuildStatus.PRODUCTION.value,
|
||||
)
|
||||
|
||||
bom_item = BomItem.objects.get(pk=6)
|
||||
@ -2133,7 +2133,7 @@ class PartAPIAggregationTest(InvenTreeAPITestCase):
|
||||
for line_item in sp.purchase_order_line_items.all():
|
||||
po = line_item.order
|
||||
|
||||
if po.status in PurchaseOrderStatus.OPEN:
|
||||
if po.status in PurchaseOrderStatusGroups.OPEN:
|
||||
remaining = line_item.quantity - line_item.received
|
||||
|
||||
if remaining > 0:
|
||||
|
@ -345,7 +345,7 @@ class PartPricingTests(InvenTreeTestCase):
|
||||
self.assertIsNone(pricing.purchase_cost_min)
|
||||
self.assertIsNone(pricing.purchase_cost_max)
|
||||
|
||||
po.status = PurchaseOrderStatus.COMPLETE
|
||||
po.status = PurchaseOrderStatus.COMPLETE.value
|
||||
po.save()
|
||||
|
||||
pricing.update_purchase_cost()
|
||||
|
Reference in New Issue
Block a user