2
0
mirror of https://github.com/inventree/InvenTree.git synced 2026-04-14 15:28:52 +00:00

Order line number (#11692)

* Add "line number" field for external orders

* Updated serializers

* Add columns to UI tables

* Update form fields

* Adds API ordering

* Bump API version

* Update CHANGELOG.md
This commit is contained in:
Oliver
2026-04-08 15:36:08 +10:00
committed by GitHub
parent 4d2ed8fcba
commit 71373e3c19
15 changed files with 131 additions and 5 deletions

View File

@@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added ### Added
- [#11692](https://github.com/inventree/InvenTree/pull/11692) adds line item numbering for external orders (purchase, sales and return orders). This allows users to specify a line number for each line item on the order, which can be used for reference purposes. The line number is optional, and can be left blank if not required. The line number is stored as a string, to allow for more flexible formatting (e.g. "1", "1.1", "A", etc).
- [#11641](https://github.com/inventree/InvenTree/pull/11641) adds support for custom parameters against the SalesOrderShipment model. - [#11641](https://github.com/inventree/InvenTree/pull/11641) adds support for custom parameters against the SalesOrderShipment model.
- [#11527](https://github.com/inventree/InvenTree/pull/11527) adds a new API endpoint for monitoring the status of a particular background task. This endpoint allows clients to check the status of a background task and receive updates when the task is complete. This is useful for long-running tasks that may take some time to complete, allowing clients to provide feedback to users about the progress of the task. - [#11527](https://github.com/inventree/InvenTree/pull/11527) adds a new API endpoint for monitoring the status of a particular background task. This endpoint allows clients to check the status of a background task and receive updates when the task is complete. This is useful for long-running tasks that may take some time to complete, allowing clients to provide feedback to users about the progress of the task.
- [#11405](https://github.com/inventree/InvenTree/pull/11405) adds default table filters, which hide inactive items by default. The default table filters are overridden by user filter selection, and only apply to the table view initially presented to the user. This means that users can still view inactive items if they choose to, but they will not be shown by default. - [#11405](https://github.com/inventree/InvenTree/pull/11405) adds default table filters, which hide inactive items by default. The default table filters are overridden by user filter selection, and only apply to the table view initially presented to the user. This means that users can still view inactive items if they choose to, but they will not be shown by default.

View File

@@ -1,11 +1,16 @@
"""InvenTree API version information.""" """InvenTree API version information."""
# InvenTree API version # InvenTree API version
INVENTREE_API_VERSION = 472 INVENTREE_API_VERSION = 473
"""Increment this API version number whenever there is a significant change to the API that any clients need to know about.""" """Increment this API version number whenever there is a significant change to the API that any clients need to know about."""
INVENTREE_API_TEXT = """ INVENTREE_API_TEXT = """
v473 -> 2026-04-08 : https://github.com/inventree/InvenTree/pull/11692
- Adds "line" field to PurchaseOrderLineItem and PurchaseOrderExtraLineItem API endpoints
- Adds "line" field to SalesOrderLineItem and SalesOrderExtraLineItem API endpoints
- Adds "line" field to ReturnOrderLineItem and ReturnOrderExtraLineItem API endpoints
v472 -> 2026-04-01 : https://github.com/inventree/InvenTree/pull/xxxx v472 -> 2026-04-01 : https://github.com/inventree/InvenTree/pull/xxxx
- Fixes writable fields on the user detail endpoint - Fixes writable fields on the user detail endpoint

View File

@@ -82,7 +82,7 @@ class GeneralExtraLineList(SerializerContextMixin, DataExportViewMixin):
filter_backends = SEARCH_ORDER_FILTER filter_backends = SEARCH_ORDER_FILTER
ordering_fields = ['quantity', 'notes', 'reference'] ordering_fields = ['quantity', 'notes', 'reference', 'line']
search_fields = ['quantity', 'notes', 'reference', 'description'] search_fields = ['quantity', 'notes', 'reference', 'description']
@@ -717,6 +717,7 @@ class PurchaseOrderLineItemList(
'order': 'order__reference', 'order': 'order__reference',
'status': 'order__status', 'status': 'order__status',
'complete_date': 'order__complete_date', 'complete_date': 'order__complete_date',
'line': ['line', 'part__SKU'],
} }
ordering_fields = [ ordering_fields = [
@@ -733,6 +734,7 @@ class PurchaseOrderLineItemList(
'order', 'order',
'status', 'status',
'complete_date', 'complete_date',
'line',
] ]
search_fields = [ search_fields = [
@@ -1067,6 +1069,7 @@ class SalesOrderLineItemList(
'reference', 'reference',
'sale_price', 'sale_price',
'target_date', 'target_date',
'line',
] ]
ordering_field_aliases = { ordering_field_aliases = {
@@ -1074,6 +1077,7 @@ class SalesOrderLineItemList(
'part': 'part__name', 'part': 'part__name',
'IPN': 'part__IPN', 'IPN': 'part__IPN',
'order': 'order__reference', 'order': 'order__reference',
'line': ['line', 'part__name'],
} }
search_fields = ['part__name', 'quantity', 'reference'] search_fields = ['part__name', 'quantity', 'reference']
@@ -1720,9 +1724,11 @@ class ReturnOrderLineItemList(
'reference', 'reference',
'target_date', 'target_date',
'received_date', 'received_date',
'line',
] ]
ordering_field_aliases = { ordering_field_aliases = {
'line': ['line', 'item__part__name'],
'part': 'item__part__name', 'part': 'item__part__name',
'IPN': 'item__part__IPN', 'IPN': 'item__part__IPN',
'stock': ['item__quantity', 'item__serial_int', 'item__serial'], 'stock': ['item__quantity', 'item__serial_int', 'item__serial'],

View File

@@ -0,0 +1,79 @@
# Generated by Django 5.2.12 on 2026-04-08 03:24
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("order", "0115_purchaseorder_updated_at_returnorder_updated_at_and_more"),
]
operations = [
migrations.AddField(
model_name="purchaseorderextraline",
name="line",
field=models.CharField(
blank=True,
default="",
help_text="Line number for this item (optional)",
max_length=20,
verbose_name="Line Number",
),
),
migrations.AddField(
model_name="purchaseorderlineitem",
name="line",
field=models.CharField(
blank=True,
default="",
help_text="Line number for this item (optional)",
max_length=20,
verbose_name="Line Number",
),
),
migrations.AddField(
model_name="returnorderextraline",
name="line",
field=models.CharField(
blank=True,
default="",
help_text="Line number for this item (optional)",
max_length=20,
verbose_name="Line Number",
),
),
migrations.AddField(
model_name="returnorderlineitem",
name="line",
field=models.CharField(
blank=True,
default="",
help_text="Line number for this item (optional)",
max_length=20,
verbose_name="Line Number",
),
),
migrations.AddField(
model_name="salesorderextraline",
name="line",
field=models.CharField(
blank=True,
default="",
help_text="Line number for this item (optional)",
max_length=20,
verbose_name="Line Number",
),
),
migrations.AddField(
model_name="salesorderlineitem",
name="line",
field=models.CharField(
blank=True,
default="",
help_text="Line number for this item (optional)",
max_length=20,
verbose_name="Line Number",
),
),
]

View File

@@ -1793,6 +1793,15 @@ class OrderLineItem(InvenTree.models.InvenTreeMetadataModel):
if self.price: if self.price:
return self.quantity * self.price return self.quantity * self.price
line = models.CharField(
max_length=20,
blank=True,
default='',
null=False,
verbose_name=_('Line Number'),
help_text=_('Line number for this item (optional)'),
)
reference = models.CharField( reference = models.CharField(
max_length=100, max_length=100,
blank=True, blank=True,

View File

@@ -276,6 +276,7 @@ class AbstractLineItemSerializer(FilterableSerializerMixin, serializers.Serializ
"""Construct a set of fields for this serializer.""" """Construct a set of fields for this serializer."""
return [ return [
'pk', 'pk',
'line',
'link', 'link',
'notes', 'notes',
'order', 'order',
@@ -309,6 +310,7 @@ class AbstractExtraLineSerializer(
"""Construct a set of fields for this serializer.""" """Construct a set of fields for this serializer."""
return [ return [
'pk', 'pk',
'line',
'description', 'description',
'link', 'link',
'notes', 'notes',

View File

@@ -83,6 +83,7 @@ export function extraLineItemFields(): ApiFormFieldSet {
order: { order: {
hidden: true hidden: true
}, },
line: {},
reference: {}, reference: {},
description: {}, description: {},
quantity: {}, quantity: {},

View File

@@ -144,6 +144,7 @@ export function usePurchaseOrderLineItemFields({
}; };
} }
}, },
line: {},
reference: {}, reference: {},
quantity: { quantity: {
onValueChange: (value) => { onValueChange: (value) => {

View File

@@ -128,8 +128,9 @@ export function useReturnOrderLineItemFields({
part_detail: true part_detail: true
} }
}, },
quantity: {}, line: {},
reference: {}, reference: {},
quantity: {},
outcome: { outcome: {
hidden: create == true hidden: create == true
}, },

View File

@@ -169,6 +169,7 @@ export function useSalesOrderLineItemFields({
}, },
onValueChange: (_: any, record?: any) => setPart(record) onValueChange: (_: any, record?: any) => setPart(record)
}, },
line: {},
reference: {}, reference: {},
quantity: { quantity: {
onValueChange: (value) => { onValueChange: (value) => {

View File

@@ -767,3 +767,13 @@ export function TotalPriceColumn(): TableColumn {
title: t`Total Price` title: t`Total Price`
}); });
} }
export function LineItemColumn(props: TableColumnProps): TableColumn {
return {
accessor: 'line',
title: t`Line Item`,
sortable: true,
switchable: true,
...props
};
}

View File

@@ -24,6 +24,7 @@ import { useUserState } from '../../states/UserState';
import { import {
DecimalColumn, DecimalColumn,
DescriptionColumn, DescriptionColumn,
LineItemColumn,
LinkColumn, LinkColumn,
NoteColumn, NoteColumn,
ProjectCodeColumn ProjectCodeColumn
@@ -50,6 +51,7 @@ export default function ExtraLineItemTable({
const tableColumns: TableColumn[] = useMemo(() => { const tableColumns: TableColumn[] = useMemo(() => {
return [ return [
LineItemColumn({}),
{ {
accessor: 'reference', accessor: 'reference',
switchable: false switchable: false
@@ -177,6 +179,7 @@ export default function ExtraLineItemTable({
params: { params: {
order: orderId order: orderId
}, },
defaultSortColumn: 'line',
rowActions: rowActions, rowActions: rowActions,
tableActions: tableActions tableActions: tableActions
}} }}

View File

@@ -36,11 +36,11 @@ import {
import useStatusCodes from '../../hooks/UseStatusCodes'; import useStatusCodes from '../../hooks/UseStatusCodes';
import { useTable } from '../../hooks/UseTable'; import { useTable } from '../../hooks/UseTable';
import { useImporterState } from '../../states/ImporterState'; import { useImporterState } from '../../states/ImporterState';
import { useGlobalSettingsState } from '../../states/SettingsStates';
import { useUserState } from '../../states/UserState'; import { useUserState } from '../../states/UserState';
import { import {
CurrencyColumn, CurrencyColumn,
DescriptionColumn, DescriptionColumn,
LineItemColumn,
LinkColumn, LinkColumn,
LocationColumn, LocationColumn,
NoteColumn, NoteColumn,
@@ -74,7 +74,6 @@ export function PurchaseOrderLineItemTable({
}>) { }>) {
const table = useTable('purchase-order-line-item'); const table = useTable('purchase-order-line-item');
const globalSettings = useGlobalSettingsState();
const navigate = useNavigate(); const navigate = useNavigate();
const user = useUserState(); const user = useUserState();
const openImporter = useImporterState((state) => state.openImporter); const openImporter = useImporterState((state) => state.openImporter);
@@ -134,6 +133,7 @@ export function PurchaseOrderLineItemTable({
const tableColumns: TableColumn[] = useMemo(() => { const tableColumns: TableColumn[] = useMemo(() => {
return [ return [
LineItemColumn({}),
PartColumn({ PartColumn({
part: 'part_detail', part: 'part_detail',
ordering: 'part_name' ordering: 'part_name'
@@ -435,6 +435,7 @@ export function PurchaseOrderLineItemTable({
props={{ props={{
enableSelection: true, enableSelection: true,
enableDownload: true, enableDownload: true,
defaultSortColumn: 'line',
params: { params: {
...params, ...params,
order: orderId, order: orderId,

View File

@@ -31,6 +31,7 @@ import { useUserState } from '../../states/UserState';
import { import {
DateColumn, DateColumn,
DescriptionColumn, DescriptionColumn,
LineItemColumn,
LinkColumn, LinkColumn,
NoteColumn, NoteColumn,
PartColumn, PartColumn,
@@ -110,6 +111,7 @@ export default function ReturnOrderLineItemTable({
const tableColumns: TableColumn[] = useMemo(() => { const tableColumns: TableColumn[] = useMemo(() => {
return [ return [
LineItemColumn({}),
PartColumn({ PartColumn({
part: 'part_detail', part: 'part_detail',
ordering: 'part' ordering: 'part'
@@ -267,6 +269,7 @@ export default function ReturnOrderLineItemTable({
item_detail: true, item_detail: true,
order_detail: true order_detail: true
}, },
defaultSortColumn: 'line',
enableSelection: enableSelection:
inProgress && user.hasChangeRole(UserRoles.return_order), inProgress && user.hasChangeRole(UserRoles.return_order),
tableActions: tableActions, tableActions: tableActions,

View File

@@ -48,6 +48,7 @@ import {
DecimalColumn, DecimalColumn,
DescriptionColumn, DescriptionColumn,
IPNColumn, IPNColumn,
LineItemColumn,
LinkColumn, LinkColumn,
ProjectCodeColumn, ProjectCodeColumn,
ReferenceColumn, ReferenceColumn,
@@ -77,6 +78,7 @@ export default function SalesOrderLineItemTable({
const tableColumns: TableColumn[] = useMemo(() => { const tableColumns: TableColumn[] = useMemo(() => {
return [ return [
LineItemColumn({}),
{ {
accessor: 'part', accessor: 'part',
sortable: true, sortable: true,
@@ -539,6 +541,7 @@ export default function SalesOrderLineItemTable({
order: orderId, order: orderId,
part_detail: true part_detail: true
}, },
defaultSortColumn: 'line',
rowActions: rowActions, rowActions: rowActions,
tableActions: tableActions, tableActions: tableActions,
tableFilters: tableFilters, tableFilters: tableFilters,