mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
PO shipped complete (#7367)
* Add new setting to bypass "shipped" status * Bypass "shipped" status optionally * Update setting description string * Update unit tests * Refactor location of status_codes * Link source code into docs * Add stock status codes * And the build order too * Fix import
This commit is contained in:
parent
fb193cae3d
commit
798c0ed322
12
docs/docs/build/build.md
vendored
12
docs/docs/build/build.md
vendored
@ -79,6 +79,18 @@ Each *Build Order* has an associated *Status* flag, which indicates the state of
|
||||
| `Cancelled` | Build has been cancelled |
|
||||
| `Completed` | Build has been completed |
|
||||
|
||||
**Source Code**
|
||||
|
||||
Refer to the source code for the Build Order status codes:
|
||||
|
||||
::: build.status_codes.BuildStatus
|
||||
options:
|
||||
show_bases: False
|
||||
show_root_heading: False
|
||||
show_root_toc_entry: False
|
||||
show_source: True
|
||||
members: []
|
||||
|
||||
### Stock Allocations
|
||||
|
||||
When a *Build Order* is created, we then have the ability to *allocate* stock items against that build order. The particular parts we need to allocate against the build are specified by the BOM for the part we are assembling.
|
||||
|
@ -22,6 +22,20 @@ Each Purchase Order has a specific status code which indicates the current state
|
||||
| In Progress | The purchase order has been issued to the supplier, and is in progress |
|
||||
| Complete | The purchase order has been completed, and is now closed |
|
||||
| Cancelled | The purchase order was cancelled, and is now closed |
|
||||
| Lost | The purchase order was lost, and is now closed |
|
||||
| Returned | The purchase order was returned, and is now closed |
|
||||
|
||||
**Source Code**
|
||||
|
||||
Refer to the source code for the Purchase Order status codes:
|
||||
|
||||
::: order.status_codes.PurchaseOrderStatus
|
||||
options:
|
||||
show_bases: False
|
||||
show_root_heading: False
|
||||
show_root_toc_entry: False
|
||||
show_source: True
|
||||
members: []
|
||||
|
||||
### Purchase Order Currency
|
||||
|
||||
|
@ -48,6 +48,18 @@ Each Return Order has a specific status code, as follows:
|
||||
| Complete | The return order was marked as complete, and is now closed |
|
||||
| Cancelled | The return order was cancelled, and is now closed |
|
||||
|
||||
**Source Code**
|
||||
|
||||
Refer to the source code for the Return Order status codes:
|
||||
|
||||
::: order.status_codes.ReturnOrderStatus
|
||||
options:
|
||||
show_bases: False
|
||||
show_root_heading: False
|
||||
show_root_toc_entry: False
|
||||
show_source: True
|
||||
members: []
|
||||
|
||||
## Create a Return Order
|
||||
|
||||
From the Return Order index, click on <span class='badge inventree add'><span class='fas fa-plus-circle'></span> New Return Order</span> which opens the "Create Return Order" form.
|
||||
|
@ -20,8 +20,23 @@ Each Sales Order has a specific status code, which represents the state of the o
|
||||
| --- | --- |
|
||||
| Pending | The sales order has been created, but has not been finalized or submitted |
|
||||
| In Progress | The sales order has been issued, and is in progress |
|
||||
| Shipped | The sales order has been completed, and is now closed |
|
||||
| Shipped | The sales order has been shipped, but is not yet complete |
|
||||
| Complete | The sales order is fully completed, and is now closed |
|
||||
| Cancelled | The sales order was cancelled, and is now closed |
|
||||
| Lost | The sales order was lost, and is now closed |
|
||||
| Returned | The sales order was returned, and is now closed |
|
||||
|
||||
**Source Code**
|
||||
|
||||
Refer to the source code for the Sales Order status codes:
|
||||
|
||||
::: order.status_codes.SalesOrderStatus
|
||||
options:
|
||||
show_bases: False
|
||||
show_root_heading: False
|
||||
show_root_toc_entry: False
|
||||
show_source: True
|
||||
members: []
|
||||
|
||||
### Sales Order Currency
|
||||
|
||||
@ -83,7 +98,7 @@ To view all the completed shipment, click on the <span class="badge inventree na
|
||||
|
||||
### Complete Order
|
||||
|
||||
Once all items in the sales order have been shipped, click on <span class="badge inventree add"><span class='fas fa-check-circle'></span> Complete Order</span> to mark the sales order as complete.
|
||||
Once all items in the sales order have been shipped, click on <span class="badge inventree add"><span class='fas fa-check-circle'></span> Complete Order</span> to mark the sales order as shipped. Confirm then click on <span class="badge inventree confirm">Submit</span> to complete the order.
|
||||
|
||||
### Cancel Order
|
||||
|
||||
|
@ -26,6 +26,18 @@ The *status* of a given stock item is displayed on the stock item detail page:
|
||||
{% include 'img.html' %}
|
||||
{% endwith %}
|
||||
|
||||
**Source Code**
|
||||
|
||||
Refer to the source code for the Stock status codes:
|
||||
|
||||
::: stock.status_codes.StockStatus
|
||||
options:
|
||||
show_bases: False
|
||||
show_root_heading: False
|
||||
show_root_toc_entry: False
|
||||
show_source: True
|
||||
members: []
|
||||
|
||||
### Default Status Code
|
||||
|
||||
The default status code for any newly created Stock Item is <span class='badge inventree success'>OK</span>
|
||||
|
@ -1,198 +1,9 @@
|
||||
"""Status codes for InvenTree."""
|
||||
"""Global import of all status codes.
|
||||
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
This file remains here for backwards compatibility,
|
||||
as external plugins may import status codes from this file.
|
||||
"""
|
||||
|
||||
from generic.states import StatusCode
|
||||
|
||||
|
||||
class PurchaseOrderStatus(StatusCode):
|
||||
"""Defines a set of status codes for a PurchaseOrder."""
|
||||
|
||||
# Order status codes
|
||||
PENDING = 10, _('Pending'), 'secondary' # Order is pending (not yet placed)
|
||||
PLACED = 20, _('Placed'), 'primary' # Order has been placed with supplier
|
||||
COMPLETE = 30, _('Complete'), 'success' # Order has been completed
|
||||
CANCELLED = 40, _('Cancelled'), 'danger' # Order was cancelled
|
||||
LOST = 50, _('Lost'), 'warning' # Order was lost
|
||||
RETURNED = 60, _('Returned'), 'warning' # Order was returned
|
||||
|
||||
|
||||
class PurchaseOrderStatusGroups:
|
||||
"""Groups for PurchaseOrderStatus codes."""
|
||||
|
||||
# Open orders
|
||||
OPEN = [PurchaseOrderStatus.PENDING.value, PurchaseOrderStatus.PLACED.value]
|
||||
|
||||
# Failed orders
|
||||
FAILED = [
|
||||
PurchaseOrderStatus.CANCELLED.value,
|
||||
PurchaseOrderStatus.LOST.value,
|
||||
PurchaseOrderStatus.RETURNED.value,
|
||||
]
|
||||
|
||||
|
||||
class SalesOrderStatus(StatusCode):
|
||||
"""Defines a set of status codes for a SalesOrder."""
|
||||
|
||||
PENDING = 10, _('Pending'), 'secondary' # Order is pending
|
||||
IN_PROGRESS = (
|
||||
15,
|
||||
_('In Progress'),
|
||||
'primary',
|
||||
) # Order has been issued, and is in progress
|
||||
SHIPPED = 20, _('Shipped'), 'success' # Order has been shipped to customer
|
||||
COMPLETE = 30, _('Complete'), 'success' # Order is complete
|
||||
CANCELLED = 40, _('Cancelled'), 'danger' # Order has been cancelled
|
||||
LOST = 50, _('Lost'), 'warning' # Order was lost
|
||||
RETURNED = 60, _('Returned'), 'warning' # Order was returned
|
||||
|
||||
|
||||
class SalesOrderStatusGroups:
|
||||
"""Groups for SalesOrderStatus codes."""
|
||||
|
||||
# Open orders
|
||||
OPEN = [SalesOrderStatus.PENDING.value, SalesOrderStatus.IN_PROGRESS.value]
|
||||
|
||||
# Completed orders
|
||||
COMPLETE = [SalesOrderStatus.SHIPPED.value, SalesOrderStatus.COMPLETE.value]
|
||||
|
||||
|
||||
class StockStatus(StatusCode):
|
||||
"""Status codes for Stock."""
|
||||
|
||||
OK = 10, _('OK'), 'success' # Item is OK
|
||||
ATTENTION = 50, _('Attention needed'), 'warning' # Item requires attention
|
||||
DAMAGED = 55, _('Damaged'), 'warning' # Item is damaged
|
||||
DESTROYED = 60, _('Destroyed'), 'danger' # Item is destroyed
|
||||
REJECTED = 65, _('Rejected'), 'danger' # Item is rejected
|
||||
LOST = 70, _('Lost'), 'dark' # Item has been lost
|
||||
QUARANTINED = (
|
||||
75,
|
||||
_('Quarantined'),
|
||||
'info',
|
||||
) # Item has been quarantined and is unavailable
|
||||
RETURNED = 85, _('Returned'), 'warning' # Item has been returned from a customer
|
||||
|
||||
|
||||
class StockStatusGroups:
|
||||
"""Groups for StockStatus codes."""
|
||||
|
||||
# The following codes correspond to parts that are 'available' or 'in stock'
|
||||
AVAILABLE_CODES = [
|
||||
StockStatus.OK.value,
|
||||
StockStatus.ATTENTION.value,
|
||||
StockStatus.DAMAGED.value,
|
||||
StockStatus.RETURNED.value,
|
||||
]
|
||||
|
||||
|
||||
class StockHistoryCode(StatusCode):
|
||||
"""Status codes for StockHistory."""
|
||||
|
||||
LEGACY = 0, _('Legacy stock tracking entry')
|
||||
|
||||
CREATED = 1, _('Stock item created')
|
||||
|
||||
# Manual editing operations
|
||||
EDITED = 5, _('Edited stock item')
|
||||
ASSIGNED_SERIAL = 6, _('Assigned serial number')
|
||||
|
||||
# Manual stock operations
|
||||
STOCK_COUNT = 10, _('Stock counted')
|
||||
STOCK_ADD = 11, _('Stock manually added')
|
||||
STOCK_REMOVE = 12, _('Stock manually removed')
|
||||
|
||||
# Location operations
|
||||
STOCK_MOVE = 20, _('Location changed')
|
||||
STOCK_UPDATE = 25, _('Stock updated')
|
||||
|
||||
# Installation operations
|
||||
INSTALLED_INTO_ASSEMBLY = 30, _('Installed into assembly')
|
||||
REMOVED_FROM_ASSEMBLY = 31, _('Removed from assembly')
|
||||
|
||||
INSTALLED_CHILD_ITEM = 35, _('Installed component item')
|
||||
REMOVED_CHILD_ITEM = 36, _('Removed component item')
|
||||
|
||||
# Stock splitting operations
|
||||
SPLIT_FROM_PARENT = 40, _('Split from parent item')
|
||||
SPLIT_CHILD_ITEM = 42, _('Split child item')
|
||||
|
||||
# Stock merging operations
|
||||
MERGED_STOCK_ITEMS = 45, _('Merged stock items')
|
||||
|
||||
# Convert stock item to variant
|
||||
CONVERTED_TO_VARIANT = 48, _('Converted to variant')
|
||||
|
||||
# Build order codes
|
||||
BUILD_OUTPUT_CREATED = 50, _('Build order output created')
|
||||
BUILD_OUTPUT_COMPLETED = 55, _('Build order output completed')
|
||||
BUILD_OUTPUT_REJECTED = 56, _('Build order output rejected')
|
||||
BUILD_CONSUMED = 57, _('Consumed by build order')
|
||||
|
||||
# Sales order codes
|
||||
SHIPPED_AGAINST_SALES_ORDER = 60, _('Shipped against Sales Order')
|
||||
|
||||
# Purchase order codes
|
||||
RECEIVED_AGAINST_PURCHASE_ORDER = 70, _('Received against Purchase Order')
|
||||
|
||||
# Return order codes
|
||||
RETURNED_AGAINST_RETURN_ORDER = 80, _('Returned against Return Order')
|
||||
|
||||
# Customer actions
|
||||
SENT_TO_CUSTOMER = 100, _('Sent to customer')
|
||||
RETURNED_FROM_CUSTOMER = 105, _('Returned from customer')
|
||||
|
||||
|
||||
class BuildStatus(StatusCode):
|
||||
"""Build status codes."""
|
||||
|
||||
PENDING = 10, _('Pending'), 'secondary' # Build is pending / active
|
||||
PRODUCTION = 20, _('Production'), 'primary' # BuildOrder is in production
|
||||
CANCELLED = 30, _('Cancelled'), 'danger' # Build was cancelled
|
||||
COMPLETE = 40, _('Complete'), 'success' # Build is complete
|
||||
|
||||
|
||||
class BuildStatusGroups:
|
||||
"""Groups for BuildStatus codes."""
|
||||
|
||||
ACTIVE_CODES = [BuildStatus.PENDING.value, BuildStatus.PRODUCTION.value]
|
||||
|
||||
|
||||
class ReturnOrderStatus(StatusCode):
|
||||
"""Defines a set of status codes for a ReturnOrder."""
|
||||
|
||||
# Order is pending, waiting for receipt of items
|
||||
PENDING = 10, _('Pending'), 'secondary'
|
||||
|
||||
# Items have been received, and are being inspected
|
||||
IN_PROGRESS = 20, _('In Progress'), 'primary'
|
||||
|
||||
COMPLETE = 30, _('Complete'), 'success'
|
||||
CANCELLED = 40, _('Cancelled'), 'danger'
|
||||
|
||||
|
||||
class ReturnOrderStatusGroups:
|
||||
"""Groups for ReturnOrderStatus codes."""
|
||||
|
||||
OPEN = [ReturnOrderStatus.PENDING.value, ReturnOrderStatus.IN_PROGRESS.value]
|
||||
|
||||
|
||||
class ReturnOrderLineStatus(StatusCode):
|
||||
"""Defines a set of status codes for a ReturnOrderLineItem."""
|
||||
|
||||
PENDING = 10, _('Pending'), 'secondary'
|
||||
|
||||
# Item is to be returned to customer, no other action
|
||||
RETURN = 20, _('Return'), 'success'
|
||||
|
||||
# Item is to be repaired, and returned to customer
|
||||
REPAIR = 30, _('Repair'), 'primary'
|
||||
|
||||
# Item is to be replaced (new item shipped)
|
||||
REPLACE = 40, _('Replace'), 'warning'
|
||||
|
||||
# Item is to be refunded (cannot be repaired)
|
||||
REFUND = 50, _('Refund'), 'info'
|
||||
|
||||
# Item is rejected
|
||||
REJECT = 60, _('Reject'), 'danger'
|
||||
from build.status_codes import *
|
||||
from order.status_codes import *
|
||||
from stock.status_codes import *
|
||||
|
@ -14,7 +14,7 @@ from django_filters import rest_framework as rest_filters
|
||||
from InvenTree.api import AttachmentMixin, APIDownloadMixin, ListCreateDestroyAPIView, MetadataView
|
||||
from generic.states.api import StatusView
|
||||
from InvenTree.helpers import str2bool, isNull, DownloadFile
|
||||
from InvenTree.status_codes import BuildStatus, BuildStatusGroups
|
||||
from build.status_codes import BuildStatus, BuildStatusGroups
|
||||
from InvenTree.mixins import CreateAPI, RetrieveUpdateDestroyAPI, ListCreateAPI
|
||||
|
||||
import common.models
|
||||
|
@ -22,7 +22,8 @@ from mptt.exceptions import InvalidMove
|
||||
|
||||
from rest_framework import serializers
|
||||
|
||||
from InvenTree.status_codes import BuildStatus, StockStatus, StockHistoryCode, BuildStatusGroups
|
||||
from build.status_codes import BuildStatus, BuildStatusGroups
|
||||
from stock.status_codes import StockStatus, StockHistoryCode
|
||||
|
||||
from build.validators import generate_next_build_reference, validate_build_order_reference
|
||||
|
||||
|
@ -18,7 +18,7 @@ from InvenTree.serializers import UserSerializer
|
||||
|
||||
import InvenTree.helpers
|
||||
from InvenTree.serializers import InvenTreeDecimalField
|
||||
from InvenTree.status_codes import StockStatus
|
||||
from stock.status_codes import StockStatus
|
||||
|
||||
from stock.generators import generate_batch_code
|
||||
from stock.models import StockItem, StockLocation
|
||||
|
20
src/backend/InvenTree/build/status_codes.py
Normal file
20
src/backend/InvenTree/build/status_codes.py
Normal file
@ -0,0 +1,20 @@
|
||||
"""Build status codes."""
|
||||
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from generic.states import StatusCode
|
||||
|
||||
|
||||
class BuildStatus(StatusCode):
|
||||
"""Build status codes."""
|
||||
|
||||
PENDING = 10, _('Pending'), 'secondary' # Build is pending / active
|
||||
PRODUCTION = 20, _('Production'), 'primary' # BuildOrder is in production
|
||||
CANCELLED = 30, _('Cancelled'), 'danger' # Build was cancelled
|
||||
COMPLETE = 40, _('Complete'), 'success' # Build is complete
|
||||
|
||||
|
||||
class BuildStatusGroups:
|
||||
"""Groups for BuildStatus codes."""
|
||||
|
||||
ACTIVE_CODES = [BuildStatus.PENDING.value, BuildStatus.PRODUCTION.value]
|
@ -17,8 +17,8 @@ import InvenTree.email
|
||||
import InvenTree.helpers
|
||||
import InvenTree.helpers_model
|
||||
import InvenTree.tasks
|
||||
from InvenTree.status_codes import BuildStatusGroups
|
||||
from InvenTree.ready import isImportingData
|
||||
from build.status_codes import BuildStatusGroups
|
||||
|
||||
import part.models as part_models
|
||||
|
||||
|
@ -10,7 +10,8 @@ from part.models import Part
|
||||
from build.models import Build, BuildItem
|
||||
from stock.models import StockItem
|
||||
|
||||
from InvenTree.status_codes import BuildStatus, StockStatus
|
||||
from build.status_codes import BuildStatus
|
||||
from stock.status_codes import StockStatus
|
||||
from InvenTree.unit_test import InvenTreeAPITestCase
|
||||
|
||||
|
||||
|
@ -11,7 +11,7 @@ from InvenTree.unit_test import InvenTreeTestCase
|
||||
from .models import Build
|
||||
from stock.models import StockItem
|
||||
|
||||
from InvenTree.status_codes import BuildStatus
|
||||
from build.status_codes import BuildStatus
|
||||
|
||||
|
||||
class BuildTestSimple(InvenTreeTestCase):
|
||||
|
@ -5,7 +5,7 @@ from django.views.generic import DetailView, ListView
|
||||
from .models import Build
|
||||
|
||||
from InvenTree.views import InvenTreeRoleMixin
|
||||
from InvenTree.status_codes import BuildStatus
|
||||
from build.status_codes import BuildStatus
|
||||
|
||||
from plugin.views import InvenTreePluginViewMixin
|
||||
|
||||
|
@ -1874,6 +1874,14 @@ class InvenTreeSetting(BaseInvenTreeSetting):
|
||||
'default': False,
|
||||
'validator': bool,
|
||||
},
|
||||
'SALESORDER_SHIP_COMPLETE': {
|
||||
'name': _('Mark Shipped Orders as Complete'),
|
||||
'description': _(
|
||||
'Sales orders marked as shipped will automatically be completed, bypassing the "shipped" status'
|
||||
),
|
||||
'default': False,
|
||||
'validator': bool,
|
||||
},
|
||||
'PURCHASEORDER_REFERENCE_PATTERN': {
|
||||
'name': _('Purchase Order Reference Pattern'),
|
||||
'description': _(
|
||||
|
@ -31,7 +31,7 @@ import InvenTree.tasks
|
||||
import InvenTree.validators
|
||||
from common.settings import currency_code_default
|
||||
from InvenTree.fields import InvenTreeURLField, RoundingDecimalField
|
||||
from InvenTree.status_codes import PurchaseOrderStatusGroups
|
||||
from order.status_codes import PurchaseOrderStatusGroups
|
||||
|
||||
|
||||
def rename_company_image(instance, filename):
|
||||
|
@ -30,14 +30,6 @@ from InvenTree.filters import SEARCH_ORDER_FILTER, SEARCH_ORDER_FILTER_ALIAS
|
||||
from InvenTree.helpers import DownloadFile, str2bool
|
||||
from InvenTree.helpers_model import construct_absolute_url, get_base_url
|
||||
from InvenTree.mixins import CreateAPI, ListAPI, ListCreateAPI, RetrieveUpdateDestroyAPI
|
||||
from InvenTree.status_codes import (
|
||||
PurchaseOrderStatus,
|
||||
PurchaseOrderStatusGroups,
|
||||
ReturnOrderLineStatus,
|
||||
ReturnOrderStatus,
|
||||
SalesOrderStatus,
|
||||
SalesOrderStatusGroups,
|
||||
)
|
||||
from order import models, serializers
|
||||
from order.admin import (
|
||||
PurchaseOrderExtraLineResource,
|
||||
@ -48,6 +40,14 @@ from order.admin import (
|
||||
SalesOrderLineItemResource,
|
||||
SalesOrderResource,
|
||||
)
|
||||
from order.status_codes import (
|
||||
PurchaseOrderStatus,
|
||||
PurchaseOrderStatusGroups,
|
||||
ReturnOrderLineStatus,
|
||||
ReturnOrderStatus,
|
||||
SalesOrderStatus,
|
||||
SalesOrderStatusGroups,
|
||||
)
|
||||
from part.models import Part
|
||||
from users.models import Owner
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
from InvenTree.status_codes import SalesOrderStatus
|
||||
from order.status_codes import SalesOrderStatus
|
||||
|
||||
|
||||
def add_shipment(apps, schema_editor):
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
from InvenTree.status_codes import SalesOrderStatus
|
||||
from order.status_codes import SalesOrderStatus
|
||||
|
||||
|
||||
def calculate_shipped_quantity(apps, schema_editor):
|
||||
|
@ -1,7 +1,7 @@
|
||||
# Generated by Django 3.2.19 on 2023-06-04 17:43
|
||||
|
||||
from django.db import migrations, models
|
||||
import InvenTree.status_codes
|
||||
import order.status_codes
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
@ -14,6 +14,6 @@ class Migration(migrations.Migration):
|
||||
migrations.AlterField(
|
||||
model_name='returnorderlineitem',
|
||||
name='outcome',
|
||||
field=models.PositiveIntegerField(choices=InvenTree.status_codes.ReturnOrderLineStatus.items(), default=10, help_text='Outcome for this line item', verbose_name='Outcome'),
|
||||
field=models.PositiveIntegerField(choices=order.status_codes.ReturnOrderLineStatus.items(), default=10, help_text='Outcome for this line item', verbose_name='Outcome'),
|
||||
),
|
||||
]
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
import django.core.validators
|
||||
from django.db import migrations, models
|
||||
import InvenTree.status_codes
|
||||
import order.status_codes
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
@ -15,6 +15,6 @@ class Migration(migrations.Migration):
|
||||
migrations.AlterField(
|
||||
model_name='salesorder',
|
||||
name='status',
|
||||
field=models.PositiveIntegerField(choices=InvenTree.status_codes.SalesOrderStatus.items(), default=10, help_text='Purchase order status', verbose_name='Status'),
|
||||
field=models.PositiveIntegerField(choices=order.status_codes.SalesOrderStatus.items(), default=10, help_text='Purchase order status', verbose_name='Status'),
|
||||
),
|
||||
]
|
||||
|
@ -45,7 +45,7 @@ from InvenTree.fields import (
|
||||
)
|
||||
from InvenTree.helpers import decimal2string, pui_url
|
||||
from InvenTree.helpers_model import getSetting, notify_responsible
|
||||
from InvenTree.status_codes import (
|
||||
from order.status_codes import (
|
||||
PurchaseOrderStatus,
|
||||
PurchaseOrderStatusGroups,
|
||||
ReturnOrderLineStatus,
|
||||
@ -53,11 +53,10 @@ from InvenTree.status_codes import (
|
||||
ReturnOrderStatusGroups,
|
||||
SalesOrderStatus,
|
||||
SalesOrderStatusGroups,
|
||||
StockHistoryCode,
|
||||
StockStatus,
|
||||
)
|
||||
from part import models as PartModels
|
||||
from plugin.events import trigger_event
|
||||
from stock.status_codes import StockHistoryCode, StockStatus
|
||||
|
||||
logger = logging.getLogger('inventree')
|
||||
|
||||
@ -1024,6 +1023,12 @@ class SalesOrder(TotalPriceMixin, Order):
|
||||
Throws a ValidationError if cannot be completed.
|
||||
"""
|
||||
try:
|
||||
if self.status == SalesOrderStatus.COMPLETE.value:
|
||||
raise ValidationError(_('Order is already complete'))
|
||||
|
||||
if self.status == SalesOrderStatus.CANCELLED.value:
|
||||
raise ValidationError(_('Order is already cancelled'))
|
||||
|
||||
# Only an open order can be marked as shipped
|
||||
if self.is_open and not self.is_completed:
|
||||
raise ValidationError(_('Only an open order can be marked as complete'))
|
||||
@ -1067,7 +1072,11 @@ class SalesOrder(TotalPriceMixin, Order):
|
||||
if not self.can_complete(**kwargs):
|
||||
return False
|
||||
|
||||
if self.status == SalesOrderStatus.SHIPPED:
|
||||
bypass_shipped = InvenTree.helpers.str2bool(
|
||||
common_models.InvenTreeSetting.get_setting('SALESORDER_SHIP_COMPLETE')
|
||||
)
|
||||
|
||||
if bypass_shipped or self.status == SalesOrderStatus.SHIPPED:
|
||||
self.status = SalesOrderStatus.COMPLETE.value
|
||||
else:
|
||||
self.status = SalesOrderStatus.SHIPPED.value
|
||||
|
@ -48,14 +48,14 @@ from InvenTree.serializers import (
|
||||
InvenTreeModelSerializer,
|
||||
InvenTreeMoneySerializer,
|
||||
)
|
||||
from InvenTree.status_codes import (
|
||||
from order.status_codes import (
|
||||
PurchaseOrderStatusGroups,
|
||||
ReturnOrderLineStatus,
|
||||
ReturnOrderStatus,
|
||||
SalesOrderStatusGroups,
|
||||
StockStatus,
|
||||
)
|
||||
from part.serializers import PartBriefSerializer
|
||||
from stock.status_codes import StockStatus
|
||||
from users.serializers import OwnerSerializer
|
||||
|
||||
|
||||
|
97
src/backend/InvenTree/order/status_codes.py
Normal file
97
src/backend/InvenTree/order/status_codes.py
Normal file
@ -0,0 +1,97 @@
|
||||
"""Order status codes."""
|
||||
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from generic.states import StatusCode
|
||||
|
||||
|
||||
class PurchaseOrderStatus(StatusCode):
|
||||
"""Defines a set of status codes for a PurchaseOrder."""
|
||||
|
||||
# Order status codes
|
||||
PENDING = 10, _('Pending'), 'secondary' # Order is pending (not yet placed)
|
||||
PLACED = 20, _('Placed'), 'primary' # Order has been placed with supplier
|
||||
COMPLETE = 30, _('Complete'), 'success' # Order has been completed
|
||||
CANCELLED = 40, _('Cancelled'), 'danger' # Order was cancelled
|
||||
LOST = 50, _('Lost'), 'warning' # Order was lost
|
||||
RETURNED = 60, _('Returned'), 'warning' # Order was returned
|
||||
|
||||
|
||||
class PurchaseOrderStatusGroups:
|
||||
"""Groups for PurchaseOrderStatus codes."""
|
||||
|
||||
# Open orders
|
||||
OPEN = [PurchaseOrderStatus.PENDING.value, PurchaseOrderStatus.PLACED.value]
|
||||
|
||||
# Failed orders
|
||||
FAILED = [
|
||||
PurchaseOrderStatus.CANCELLED.value,
|
||||
PurchaseOrderStatus.LOST.value,
|
||||
PurchaseOrderStatus.RETURNED.value,
|
||||
]
|
||||
|
||||
|
||||
class SalesOrderStatus(StatusCode):
|
||||
"""Defines a set of status codes for a SalesOrder."""
|
||||
|
||||
PENDING = 10, _('Pending'), 'secondary' # Order is pending
|
||||
IN_PROGRESS = (
|
||||
15,
|
||||
_('In Progress'),
|
||||
'primary',
|
||||
) # Order has been issued, and is in progress
|
||||
SHIPPED = 20, _('Shipped'), 'success' # Order has been shipped to customer
|
||||
COMPLETE = 30, _('Complete'), 'success' # Order is complete
|
||||
CANCELLED = 40, _('Cancelled'), 'danger' # Order has been cancelled
|
||||
LOST = 50, _('Lost'), 'warning' # Order was lost
|
||||
RETURNED = 60, _('Returned'), 'warning' # Order was returned
|
||||
|
||||
|
||||
class SalesOrderStatusGroups:
|
||||
"""Groups for SalesOrderStatus codes."""
|
||||
|
||||
# Open orders
|
||||
OPEN = [SalesOrderStatus.PENDING.value, SalesOrderStatus.IN_PROGRESS.value]
|
||||
|
||||
# Completed orders
|
||||
COMPLETE = [SalesOrderStatus.SHIPPED.value, SalesOrderStatus.COMPLETE.value]
|
||||
|
||||
|
||||
class ReturnOrderStatus(StatusCode):
|
||||
"""Defines a set of status codes for a ReturnOrder."""
|
||||
|
||||
# Order is pending, waiting for receipt of items
|
||||
PENDING = 10, _('Pending'), 'secondary'
|
||||
|
||||
# Items have been received, and are being inspected
|
||||
IN_PROGRESS = 20, _('In Progress'), 'primary'
|
||||
|
||||
COMPLETE = 30, _('Complete'), 'success'
|
||||
CANCELLED = 40, _('Cancelled'), 'danger'
|
||||
|
||||
|
||||
class ReturnOrderStatusGroups:
|
||||
"""Groups for ReturnOrderStatus codes."""
|
||||
|
||||
OPEN = [ReturnOrderStatus.PENDING.value, ReturnOrderStatus.IN_PROGRESS.value]
|
||||
|
||||
|
||||
class ReturnOrderLineStatus(StatusCode):
|
||||
"""Defines a set of status codes for a ReturnOrderLineItem."""
|
||||
|
||||
PENDING = 10, _('Pending'), 'secondary'
|
||||
|
||||
# Item is to be returned to customer, no other action
|
||||
RETURN = 20, _('Return'), 'success'
|
||||
|
||||
# Item is to be repaired, and returned to customer
|
||||
REPAIR = 30, _('Repair'), 'primary'
|
||||
|
||||
# Item is to be replaced (new item shipped)
|
||||
REPLACE = 40, _('Replace'), 'warning'
|
||||
|
||||
# Item is to be refunded (cannot be repaired)
|
||||
REFUND = 50, _('Refund'), 'info'
|
||||
|
||||
# Item is rejected
|
||||
REJECT = 60, _('Reject'), 'danger'
|
@ -7,8 +7,8 @@ from django.utils.translation import gettext_lazy as _
|
||||
import common.notifications
|
||||
import InvenTree.helpers_model
|
||||
import order.models
|
||||
from InvenTree.status_codes import PurchaseOrderStatusGroups, SalesOrderStatusGroups
|
||||
from InvenTree.tasks import ScheduledTask, scheduled_task
|
||||
from order.status_codes import PurchaseOrderStatusGroups, SalesOrderStatusGroups
|
||||
from plugin.events import trigger_event
|
||||
|
||||
|
||||
|
@ -16,18 +16,18 @@ from rest_framework import status
|
||||
from common.models import InvenTreeSetting
|
||||
from common.settings import currency_codes
|
||||
from company.models import Company, SupplierPart, SupplierPriceBreak
|
||||
from InvenTree.status_codes import (
|
||||
from InvenTree.unit_test import InvenTreeAPITestCase
|
||||
from order import models
|
||||
from order.status_codes import (
|
||||
PurchaseOrderStatus,
|
||||
ReturnOrderLineStatus,
|
||||
ReturnOrderStatus,
|
||||
SalesOrderStatus,
|
||||
SalesOrderStatusGroups,
|
||||
StockStatus,
|
||||
)
|
||||
from InvenTree.unit_test import InvenTreeAPITestCase
|
||||
from order import models
|
||||
from part.models import Part
|
||||
from stock.models import StockItem
|
||||
from stock.status_codes import StockStatus
|
||||
from users.models import Owner
|
||||
|
||||
|
||||
@ -1476,6 +1476,77 @@ class SalesOrderTest(OrderTest):
|
||||
expected_fn=f'InvenTree_SalesOrders.{fmt}',
|
||||
)
|
||||
|
||||
def test_sales_order_complete(self):
|
||||
"""Tests for marking a SalesOrder as complete."""
|
||||
self.assignRole('sales_order.add')
|
||||
|
||||
# Let's create a SalesOrder
|
||||
customer = Company.objects.filter(is_customer=True).first()
|
||||
so = models.SalesOrder.objects.create(
|
||||
customer=customer, reference='SO-12345', description='Test SO'
|
||||
)
|
||||
|
||||
self.assertEqual(so.status, SalesOrderStatus.PENDING.value)
|
||||
|
||||
# Create a line item
|
||||
part = Part.objects.filter(salable=True).first()
|
||||
|
||||
line = models.SalesOrderLineItem.objects.create(
|
||||
order=so, part=part, quantity=10, sale_price=Money(10, 'USD')
|
||||
)
|
||||
|
||||
shipment = so.shipments.first()
|
||||
|
||||
if shipment is None:
|
||||
shipment = models.SalesOrderShipment.objects.create(
|
||||
order=so, reference='SHIP-12345'
|
||||
)
|
||||
|
||||
# Allocate some stock
|
||||
item = StockItem.objects.create(part=part, quantity=100, location=None)
|
||||
models.SalesOrderAllocation.objects.create(
|
||||
quantity=10, line=line, item=item, shipment=shipment
|
||||
)
|
||||
|
||||
# Ship the shipment
|
||||
shipment.complete_shipment(self.user)
|
||||
|
||||
# Ok, now we should be able to "complete" the shipment via the API
|
||||
# The 'SALESORDER_SHIP_COMPLETE' setting determines if the outcome is "SHIPPED" or "COMPLETE"
|
||||
InvenTreeSetting.set_setting('SALESORDER_SHIP_COMPLETE', False)
|
||||
|
||||
url = reverse('api-so-complete', kwargs={'pk': so.pk})
|
||||
self.post(url, {}, expected_code=201)
|
||||
|
||||
so.refresh_from_db()
|
||||
self.assertEqual(so.status, SalesOrderStatus.SHIPPED.value)
|
||||
|
||||
# Now, let's try to "complete" the shipment again
|
||||
# This time it should get marked as "COMPLETE"
|
||||
self.post(url, {}, expected_code=201)
|
||||
|
||||
so.refresh_from_db()
|
||||
self.assertEqual(so.status, SalesOrderStatus.COMPLETE.value)
|
||||
|
||||
# Now, let's try *again* (it should fail as the order is already complete)
|
||||
response = self.post(url, {}, expected_code=400)
|
||||
|
||||
self.assertIn('Order is already complete', str(response.data))
|
||||
|
||||
# Next, we'll change the setting so that the order status jumps straight to "complete"
|
||||
so.status = SalesOrderStatus.PENDING.value
|
||||
so.save()
|
||||
so.refresh_from_db()
|
||||
self.assertEqual(so.status, SalesOrderStatus.PENDING.value)
|
||||
|
||||
InvenTreeSetting.set_setting('SALESORDER_SHIP_COMPLETE', True)
|
||||
|
||||
self.post(url, {}, expected_code=201)
|
||||
|
||||
# The orders status should now be "complete" (not "shipped")
|
||||
so.refresh_from_db()
|
||||
self.assertEqual(so.status, SalesOrderStatus.COMPLETE.value)
|
||||
|
||||
|
||||
class SalesOrderLineItemTest(OrderTest):
|
||||
"""Tests for the SalesOrderLineItem API."""
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
from django_test_migrations.contrib.unittest_case import MigratorTestCase
|
||||
|
||||
from InvenTree.status_codes import SalesOrderStatus
|
||||
from order.status_codes import SalesOrderStatus
|
||||
|
||||
|
||||
class TestRefIntMigrations(MigratorTestCase):
|
||||
|
@ -14,7 +14,7 @@ from djmoney.money import Money
|
||||
import common.models
|
||||
import order.tasks
|
||||
from company.models import Company, SupplierPart
|
||||
from InvenTree.status_codes import PurchaseOrderStatus
|
||||
from order.status_codes import PurchaseOrderStatus
|
||||
from part.models import Part
|
||||
from stock.models import StockItem, StockLocation
|
||||
from users.models import Owner
|
||||
|
@ -18,6 +18,7 @@ from rest_framework.response import Response
|
||||
import order.models
|
||||
import part.filters
|
||||
from build.models import Build, BuildItem
|
||||
from build.status_codes import BuildStatusGroups
|
||||
from InvenTree.api import (
|
||||
APIDownloadMixin,
|
||||
AttachmentMixin,
|
||||
@ -45,11 +46,7 @@ from InvenTree.mixins import (
|
||||
)
|
||||
from InvenTree.permissions import RolePermission
|
||||
from InvenTree.serializers import EmptySerializer
|
||||
from InvenTree.status_codes import (
|
||||
BuildStatusGroups,
|
||||
PurchaseOrderStatusGroups,
|
||||
SalesOrderStatusGroups,
|
||||
)
|
||||
from order.status_codes import PurchaseOrderStatusGroups, SalesOrderStatusGroups
|
||||
from part.admin import PartCategoryResource, PartResource
|
||||
from stock.models import StockLocation
|
||||
|
||||
|
@ -40,11 +40,8 @@ from sql_util.utils import SubquerySum
|
||||
|
||||
import part.models
|
||||
import stock.models
|
||||
from InvenTree.status_codes import (
|
||||
BuildStatusGroups,
|
||||
PurchaseOrderStatusGroups,
|
||||
SalesOrderStatusGroups,
|
||||
)
|
||||
from build.status_codes import BuildStatusGroups
|
||||
from order.status_codes import PurchaseOrderStatusGroups, SalesOrderStatusGroups
|
||||
|
||||
|
||||
def annotate_in_production_quantity(reference=''):
|
||||
|
@ -46,20 +46,20 @@ import part.settings as part_settings
|
||||
import report.mixins
|
||||
import users.models
|
||||
from build import models as BuildModels
|
||||
from build.status_codes import BuildStatusGroups
|
||||
from common.models import InvenTreeSetting
|
||||
from common.settings import currency_code_default
|
||||
from company.models import SupplierPart
|
||||
from InvenTree import helpers, validators
|
||||
from InvenTree.fields import InvenTreeURLField
|
||||
from InvenTree.helpers import decimal2money, decimal2string, normalize, str2bool
|
||||
from InvenTree.status_codes import (
|
||||
BuildStatusGroups,
|
||||
from order import models as OrderModels
|
||||
from order.status_codes import (
|
||||
PurchaseOrderStatus,
|
||||
PurchaseOrderStatusGroups,
|
||||
SalesOrderStatus,
|
||||
SalesOrderStatusGroups,
|
||||
)
|
||||
from order import models as OrderModels
|
||||
from stock import models as StockModels
|
||||
|
||||
logger = logging.getLogger('inventree')
|
||||
|
@ -33,7 +33,7 @@ import part.stocktake
|
||||
import part.tasks
|
||||
import stock.models
|
||||
import users.models
|
||||
from InvenTree.status_codes import BuildStatusGroups
|
||||
from build.status_codes import BuildStatusGroups
|
||||
from InvenTree.tasks import offload_task
|
||||
|
||||
from .models import (
|
||||
|
@ -19,11 +19,12 @@ from rest_framework.test import APIClient
|
||||
import build.models
|
||||
import company.models
|
||||
import order.models
|
||||
from build.status_codes import BuildStatus
|
||||
from common.models import InvenTreeSetting
|
||||
from company.models import Company, SupplierPart
|
||||
from InvenTree.settings import BASE_DIR
|
||||
from InvenTree.status_codes import BuildStatus, PurchaseOrderStatusGroups, StockStatus
|
||||
from InvenTree.unit_test import InvenTreeAPITestCase
|
||||
from order.status_codes import PurchaseOrderStatusGroups
|
||||
from part.models import (
|
||||
BomItem,
|
||||
BomItemSubstitute,
|
||||
@ -37,6 +38,7 @@ from part.models import (
|
||||
PartTestTemplate,
|
||||
)
|
||||
from stock.models import StockItem, StockLocation
|
||||
from stock.status_codes import StockStatus
|
||||
|
||||
|
||||
class PartCategoryAPITest(InvenTreeAPITestCase):
|
||||
|
@ -11,8 +11,8 @@ import company.models
|
||||
import order.models
|
||||
import part.models
|
||||
import stock.models
|
||||
from InvenTree.status_codes import PurchaseOrderStatus
|
||||
from InvenTree.unit_test import InvenTreeTestCase
|
||||
from order.status_codes import PurchaseOrderStatus
|
||||
|
||||
|
||||
class PartPricingTests(InvenTreeTestCase):
|
||||
|
@ -7,7 +7,7 @@ from rest_framework import serializers
|
||||
|
||||
import order.models
|
||||
import stock.models
|
||||
from InvenTree.status_codes import PurchaseOrderStatus, SalesOrderStatus
|
||||
from order.status_codes import PurchaseOrderStatus, SalesOrderStatus
|
||||
from plugin.builtin.barcodes.inventree_barcode import InvenTreeInternalBarcodePlugin
|
||||
|
||||
|
||||
|
@ -2,8 +2,8 @@
|
||||
|
||||
from common.notifications import trigger_notification
|
||||
from generic.states import TransitionMethod
|
||||
from InvenTree.status_codes import ReturnOrderStatus
|
||||
from order.models import ReturnOrder
|
||||
from order.status_codes import ReturnOrderStatus
|
||||
from plugin import InvenTreePlugin
|
||||
|
||||
|
||||
|
@ -56,7 +56,6 @@ from InvenTree.mixins import (
|
||||
RetrieveAPI,
|
||||
RetrieveUpdateDestroyAPI,
|
||||
)
|
||||
from InvenTree.status_codes import StockHistoryCode, StockStatus
|
||||
from order.models import PurchaseOrder, ReturnOrder, SalesOrder, SalesOrderAllocation
|
||||
from order.serializers import (
|
||||
PurchaseOrderSerializer,
|
||||
@ -75,6 +74,7 @@ from stock.models import (
|
||||
StockLocation,
|
||||
StockLocationType,
|
||||
)
|
||||
from stock.status_codes import StockHistoryCode, StockStatus
|
||||
|
||||
|
||||
class GenerateBatchCode(GenericAPIView):
|
||||
|
@ -4,7 +4,7 @@ import re
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
from InvenTree.status_codes import StockHistoryCode
|
||||
from stock.status_codes import StockHistoryCode
|
||||
|
||||
|
||||
def update_history(apps, schema_editor):
|
||||
|
@ -15,7 +15,7 @@ def update_stock_history(apps, schema_editor):
|
||||
- Add the appropriate history!
|
||||
"""
|
||||
|
||||
from InvenTree.status_codes import StockHistoryCode
|
||||
from stock.status_codes import StockHistoryCode
|
||||
|
||||
StockItem = apps.get_model('stock', 'stockitem')
|
||||
StockItemTracking = apps.get_model('stock', 'stockitemtracking')
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
import django.core.validators
|
||||
from django.db import migrations, models
|
||||
import InvenTree.status_codes
|
||||
import stock.status_codes
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
@ -15,6 +15,6 @@ class Migration(migrations.Migration):
|
||||
migrations.AlterField(
|
||||
model_name='stockitem',
|
||||
name='status',
|
||||
field=models.PositiveIntegerField(choices=InvenTree.status_codes.StockStatus.items(), default=10, validators=[django.core.validators.MinValueValidator(0)]),
|
||||
field=models.PositiveIntegerField(choices=stock.status_codes.StockStatus.items(), default=10, validators=[django.core.validators.MinValueValidator(0)]),
|
||||
),
|
||||
]
|
||||
|
@ -34,15 +34,11 @@ import report.mixins
|
||||
import report.models
|
||||
from company import models as CompanyModels
|
||||
from InvenTree.fields import InvenTreeModelMoneyField, InvenTreeURLField
|
||||
from InvenTree.status_codes import (
|
||||
SalesOrderStatusGroups,
|
||||
StockHistoryCode,
|
||||
StockStatus,
|
||||
StockStatusGroups,
|
||||
)
|
||||
from order.status_codes import SalesOrderStatusGroups
|
||||
from part import models as PartModels
|
||||
from plugin.events import trigger_event
|
||||
from stock.generators import generate_batch_code
|
||||
from stock.status_codes import StockHistoryCode, StockStatus, StockStatusGroups
|
||||
from users.models import Owner
|
||||
|
||||
logger = logging.getLogger('inventree')
|
||||
@ -348,7 +344,7 @@ class StockItem(
|
||||
stocktake_user: User that performed the most recent stocktake
|
||||
review_needed: Flag if StockItem needs review
|
||||
delete_on_deplete: If True, StockItem will be deleted when the stock level gets to zero
|
||||
status: Status of this StockItem (ref: InvenTree.status_codes.StockStatus)
|
||||
status: Status of this StockItem (ref: stock.status_codes.StockStatus)
|
||||
notes: Extra notes field
|
||||
build: Link to a Build (if this stock item was created from a build)
|
||||
is_building: Boolean field indicating if this stock item is currently being built (or is "in production")
|
||||
|
@ -20,11 +20,11 @@ import common.models
|
||||
import company.models
|
||||
import InvenTree.helpers
|
||||
import InvenTree.serializers
|
||||
import InvenTree.status_codes
|
||||
import order.models
|
||||
import part.filters as part_filters
|
||||
import part.models as part_models
|
||||
import stock.filters
|
||||
import stock.status_codes
|
||||
from company.serializers import SupplierPartSerializer
|
||||
from InvenTree.serializers import InvenTreeCurrencySerializer, InvenTreeDecimalField
|
||||
from part.serializers import PartBriefSerializer, PartTestTemplateSerializer
|
||||
@ -925,8 +925,8 @@ class StockChangeStatusSerializer(serializers.Serializer):
|
||||
return items
|
||||
|
||||
status = serializers.ChoiceField(
|
||||
choices=InvenTree.status_codes.StockStatus.items(),
|
||||
default=InvenTree.status_codes.StockStatus.OK.value,
|
||||
choices=stock.status_codes.StockStatus.items(),
|
||||
default=stock.status_codes.StockStatus.OK.value,
|
||||
label=_('Status'),
|
||||
)
|
||||
|
||||
@ -973,7 +973,7 @@ class StockChangeStatusSerializer(serializers.Serializer):
|
||||
transaction_notes.append(
|
||||
StockItemTracking(
|
||||
item=item,
|
||||
tracking_type=InvenTree.status_codes.StockHistoryCode.EDITED.value,
|
||||
tracking_type=stock.status_codes.StockHistoryCode.EDITED.value,
|
||||
date=now,
|
||||
deltas=deltas,
|
||||
user=user,
|
||||
@ -1419,7 +1419,7 @@ def stock_item_adjust_status_options():
|
||||
|
||||
In particular, include a Null option for the status field.
|
||||
"""
|
||||
return [(None, _('No Change'))] + InvenTree.status_codes.StockStatus.items()
|
||||
return [(None, _('No Change'))] + stock.status_codes.StockStatus.items()
|
||||
|
||||
|
||||
class StockAdjustmentItemSerializer(serializers.Serializer):
|
||||
|
91
src/backend/InvenTree/stock/status_codes.py
Normal file
91
src/backend/InvenTree/stock/status_codes.py
Normal file
@ -0,0 +1,91 @@
|
||||
"""Stock status codes."""
|
||||
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from generic.states import StatusCode
|
||||
|
||||
|
||||
class StockStatus(StatusCode):
|
||||
"""Status codes for Stock."""
|
||||
|
||||
OK = 10, _('OK'), 'success' # Item is OK
|
||||
ATTENTION = 50, _('Attention needed'), 'warning' # Item requires attention
|
||||
DAMAGED = 55, _('Damaged'), 'warning' # Item is damaged
|
||||
DESTROYED = 60, _('Destroyed'), 'danger' # Item is destroyed
|
||||
REJECTED = 65, _('Rejected'), 'danger' # Item is rejected
|
||||
LOST = 70, _('Lost'), 'dark' # Item has been lost
|
||||
QUARANTINED = (
|
||||
75,
|
||||
_('Quarantined'),
|
||||
'info',
|
||||
) # Item has been quarantined and is unavailable
|
||||
RETURNED = 85, _('Returned'), 'warning' # Item has been returned from a customer
|
||||
|
||||
|
||||
class StockStatusGroups:
|
||||
"""Groups for StockStatus codes."""
|
||||
|
||||
# The following codes correspond to parts that are 'available' or 'in stock'
|
||||
AVAILABLE_CODES = [
|
||||
StockStatus.OK.value,
|
||||
StockStatus.ATTENTION.value,
|
||||
StockStatus.DAMAGED.value,
|
||||
StockStatus.RETURNED.value,
|
||||
]
|
||||
|
||||
|
||||
class StockHistoryCode(StatusCode):
|
||||
"""Status codes for StockHistory."""
|
||||
|
||||
LEGACY = 0, _('Legacy stock tracking entry')
|
||||
|
||||
CREATED = 1, _('Stock item created')
|
||||
|
||||
# Manual editing operations
|
||||
EDITED = 5, _('Edited stock item')
|
||||
ASSIGNED_SERIAL = 6, _('Assigned serial number')
|
||||
|
||||
# Manual stock operations
|
||||
STOCK_COUNT = 10, _('Stock counted')
|
||||
STOCK_ADD = 11, _('Stock manually added')
|
||||
STOCK_REMOVE = 12, _('Stock manually removed')
|
||||
|
||||
# Location operations
|
||||
STOCK_MOVE = 20, _('Location changed')
|
||||
STOCK_UPDATE = 25, _('Stock updated')
|
||||
|
||||
# Installation operations
|
||||
INSTALLED_INTO_ASSEMBLY = 30, _('Installed into assembly')
|
||||
REMOVED_FROM_ASSEMBLY = 31, _('Removed from assembly')
|
||||
|
||||
INSTALLED_CHILD_ITEM = 35, _('Installed component item')
|
||||
REMOVED_CHILD_ITEM = 36, _('Removed component item')
|
||||
|
||||
# Stock splitting operations
|
||||
SPLIT_FROM_PARENT = 40, _('Split from parent item')
|
||||
SPLIT_CHILD_ITEM = 42, _('Split child item')
|
||||
|
||||
# Stock merging operations
|
||||
MERGED_STOCK_ITEMS = 45, _('Merged stock items')
|
||||
|
||||
# Convert stock item to variant
|
||||
CONVERTED_TO_VARIANT = 48, _('Converted to variant')
|
||||
|
||||
# Build order codes
|
||||
BUILD_OUTPUT_CREATED = 50, _('Build order output created')
|
||||
BUILD_OUTPUT_COMPLETED = 55, _('Build order output completed')
|
||||
BUILD_OUTPUT_REJECTED = 56, _('Build order output rejected')
|
||||
BUILD_CONSUMED = 57, _('Consumed by build order')
|
||||
|
||||
# Sales order codes
|
||||
SHIPPED_AGAINST_SALES_ORDER = 60, _('Shipped against Sales Order')
|
||||
|
||||
# Purchase order codes
|
||||
RECEIVED_AGAINST_PURCHASE_ORDER = 70, _('Received against Purchase Order')
|
||||
|
||||
# Return order codes
|
||||
RETURNED_AGAINST_RETURN_ORDER = 80, _('Returned against Return Order')
|
||||
|
||||
# Customer actions
|
||||
SENT_TO_CUSTOMER = 100, _('Sent to customer')
|
||||
RETURNED_FROM_CUSTOMER = 105, _('Returned from customer')
|
@ -17,7 +17,6 @@ import build.models
|
||||
import company.models
|
||||
import part.models
|
||||
from common.models import InvenTreeSetting
|
||||
from InvenTree.status_codes import StockHistoryCode, StockStatus
|
||||
from InvenTree.unit_test import InvenTreeAPITestCase
|
||||
from part.models import Part, PartTestTemplate
|
||||
from stock.models import (
|
||||
@ -26,6 +25,7 @@ from stock.models import (
|
||||
StockLocation,
|
||||
StockLocationType,
|
||||
)
|
||||
from stock.status_codes import StockHistoryCode, StockStatus
|
||||
|
||||
|
||||
class StockAPITestCase(InvenTreeAPITestCase):
|
||||
|
@ -5,9 +5,9 @@ from django.test import tag
|
||||
from django.urls import reverse
|
||||
|
||||
from common.models import InvenTreeSetting
|
||||
from InvenTree.status_codes import StockStatus
|
||||
from InvenTree.unit_test import InvenTreeTestCase
|
||||
from stock.models import StockItem, StockLocation
|
||||
from stock.status_codes import StockStatus
|
||||
from users.models import Owner
|
||||
|
||||
|
||||
|
@ -10,10 +10,10 @@ from django.test import override_settings
|
||||
from build.models import Build
|
||||
from common.models import InvenTreeSetting
|
||||
from company.models import Company
|
||||
from InvenTree.status_codes import StockHistoryCode
|
||||
from InvenTree.unit_test import InvenTreeTestCase
|
||||
from order.models import SalesOrder
|
||||
from part.models import Part, PartTestTemplate
|
||||
from stock.status_codes import StockHistoryCode
|
||||
|
||||
from .models import StockItem, StockItemTestResult, StockItemTracking, StockLocation
|
||||
|
||||
|
@ -15,6 +15,7 @@
|
||||
{% include "InvenTree/settings/setting.html" with key="SALESORDER_REQUIRE_RESPONSIBLE" %}
|
||||
{% include "InvenTree/settings/setting.html" with key="SALESORDER_DEFAULT_SHIPMENT" icon="fa-truck-loading" %}
|
||||
{% include "InvenTree/settings/setting.html" with key="SALESORDER_EDIT_COMPLETED_ORDERS" icon='fa-edit' %}
|
||||
{% include "InvenTree/settings/setting.html" with key="SALESORDER_SHIP_COMPLETE" %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
@ -263,7 +263,8 @@ export default function SystemSettings() {
|
||||
'SALESORDER_REFERENCE_PATTERN',
|
||||
'SALESORDER_REQUIRE_RESPONSIBLE',
|
||||
'SALESORDER_DEFAULT_SHIPMENT',
|
||||
'SALESORDER_EDIT_COMPLETED_ORDERS'
|
||||
'SALESORDER_EDIT_COMPLETED_ORDERS',
|
||||
'SALESORDER_SHIP_COMPLETE'
|
||||
]}
|
||||
/>
|
||||
)
|
||||
|
Loading…
Reference in New Issue
Block a user