mirror of
https://github.com/inventree/InvenTree.git
synced 2025-11-13 19:36:46 +00:00
[UI] Order form improvements (#10802)
* Auto-fill supplier parts in order wizard * Copy supplier part SKU from order parts wizard * Add "on_order" filter to BuildLine table * Allow ordering by production and ordering quantities * Allow specification of purchase price * Bump API version * Adjust UI testings
This commit is contained in:
@@ -1,12 +1,16 @@
|
|||||||
"""InvenTree API version information."""
|
"""InvenTree API version information."""
|
||||||
|
|
||||||
# InvenTree API version
|
# InvenTree API version
|
||||||
INVENTREE_API_VERSION = 424
|
INVENTREE_API_VERSION = 425
|
||||||
"""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 = """
|
||||||
|
|
||||||
v424 -> 2025-11-05 : https://github.com/inventree/InvenTree/pull/10730
|
v425 -> 2025-11-11 : https://github.com/inventree/InvenTree/pull/10802
|
||||||
|
- Adds "on_order" filter to the BuildLine API endpoint
|
||||||
|
- Allow BuildLine list to be ordered by "on_order" and "in_production" fields
|
||||||
|
|
||||||
|
v424 -> 2025-11-11 : https://github.com/inventree/InvenTree/pull/10730
|
||||||
- Adds more lower / upper bounds to integer fields in the API schema due to bump to Django 5.2- no functional changes
|
- Adds more lower / upper bounds to integer fields in the API schema due to bump to Django 5.2- no functional changes
|
||||||
|
|
||||||
v423 -> 2025-11-05 : https://github.com/inventree/InvenTree/pull/10772
|
v423 -> 2025-11-05 : https://github.com/inventree/InvenTree/pull/10772
|
||||||
|
|||||||
@@ -520,6 +520,15 @@ class BuildLineFilter(FilterSet):
|
|||||||
return queryset.filter(flt)
|
return queryset.filter(flt)
|
||||||
return queryset.exclude(flt)
|
return queryset.exclude(flt)
|
||||||
|
|
||||||
|
on_order = rest_filters.BooleanFilter(label=_('On Order'), method='filter_on_order')
|
||||||
|
|
||||||
|
def filter_on_order(self, queryset, name, value):
|
||||||
|
"""Filter by whether there is stock on order for each BuildLine."""
|
||||||
|
if str2bool(value):
|
||||||
|
return queryset.filter(on_order__gt=0)
|
||||||
|
else:
|
||||||
|
return queryset.filter(on_order=0)
|
||||||
|
|
||||||
|
|
||||||
class BuildLineMixin(SerializerContextMixin):
|
class BuildLineMixin(SerializerContextMixin):
|
||||||
"""Mixin class for BuildLine API endpoints."""
|
"""Mixin class for BuildLine API endpoints."""
|
||||||
@@ -606,6 +615,8 @@ class BuildLineList(
|
|||||||
'trackable',
|
'trackable',
|
||||||
'allow_variants',
|
'allow_variants',
|
||||||
'inherited',
|
'inherited',
|
||||||
|
'on_order',
|
||||||
|
'scheduled_to_build',
|
||||||
]
|
]
|
||||||
|
|
||||||
ordering_field_aliases = {
|
ordering_field_aliases = {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import {
|
|||||||
ActionIcon,
|
ActionIcon,
|
||||||
Button,
|
Button,
|
||||||
type DefaultMantineColor,
|
type DefaultMantineColor,
|
||||||
|
type FloatingPosition,
|
||||||
CopyButton as MantineCopyButton,
|
CopyButton as MantineCopyButton,
|
||||||
type MantineSize,
|
type MantineSize,
|
||||||
Text,
|
Text,
|
||||||
@@ -16,12 +17,18 @@ import type { JSX } from 'react';
|
|||||||
export function CopyButton({
|
export function CopyButton({
|
||||||
value,
|
value,
|
||||||
label,
|
label,
|
||||||
|
tooltip,
|
||||||
|
disabled,
|
||||||
|
tooltipPosition,
|
||||||
content,
|
content,
|
||||||
size,
|
size,
|
||||||
color = 'gray'
|
color = 'gray'
|
||||||
}: Readonly<{
|
}: Readonly<{
|
||||||
value: any;
|
value: any;
|
||||||
label?: string;
|
label?: string;
|
||||||
|
tooltip?: string;
|
||||||
|
disabled?: boolean;
|
||||||
|
tooltipPosition?: FloatingPosition;
|
||||||
content?: JSX.Element;
|
content?: JSX.Element;
|
||||||
size?: MantineSize;
|
size?: MantineSize;
|
||||||
color?: DefaultMantineColor;
|
color?: DefaultMantineColor;
|
||||||
@@ -31,8 +38,13 @@ export function CopyButton({
|
|||||||
return (
|
return (
|
||||||
<MantineCopyButton value={value}>
|
<MantineCopyButton value={value}>
|
||||||
{({ copied, copy }) => (
|
{({ copied, copy }) => (
|
||||||
<Tooltip label={copied ? t`Copied` : t`Copy`} withArrow>
|
<Tooltip
|
||||||
|
label={copied ? t`Copied` : (tooltip ?? t`Copy`)}
|
||||||
|
withArrow
|
||||||
|
position={tooltipPosition}
|
||||||
|
>
|
||||||
<ButtonComponent
|
<ButtonComponent
|
||||||
|
disabled={disabled}
|
||||||
color={copied ? 'teal' : color}
|
color={copied ? 'teal' : color}
|
||||||
onClick={copy}
|
onClick={copy}
|
||||||
variant='transparent'
|
variant='transparent'
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ import { useCreateApiFormModal } from '../../hooks/UseForm';
|
|||||||
import { useInstance } from '../../hooks/UseInstance';
|
import { useInstance } from '../../hooks/UseInstance';
|
||||||
import useWizard from '../../hooks/UseWizard';
|
import useWizard from '../../hooks/UseWizard';
|
||||||
import { RenderPartColumn } from '../../tables/ColumnRenderers';
|
import { RenderPartColumn } from '../../tables/ColumnRenderers';
|
||||||
|
import { CopyButton } from '../buttons/CopyButton';
|
||||||
import RemoveRowButton from '../buttons/RemoveRowButton';
|
import RemoveRowButton from '../buttons/RemoveRowButton';
|
||||||
import { StandaloneField } from '../forms/StandaloneField';
|
import { StandaloneField } from '../forms/StandaloneField';
|
||||||
import Expand from '../items/Expand';
|
import Expand from '../items/Expand';
|
||||||
@@ -235,6 +236,8 @@ function SelectPartsStep({
|
|||||||
quantity: {
|
quantity: {
|
||||||
// TODO: Auto-fill with the desired quantity
|
// TODO: Auto-fill with the desired quantity
|
||||||
},
|
},
|
||||||
|
purchase_price: {},
|
||||||
|
purchase_price_currency: {},
|
||||||
merge_items: {}
|
merge_items: {}
|
||||||
};
|
};
|
||||||
}, [selectedRecord]);
|
}, [selectedRecord]);
|
||||||
@@ -299,6 +302,7 @@ function SelectPartsStep({
|
|||||||
model: ModelType.supplierpart,
|
model: ModelType.supplierpart,
|
||||||
placeholder: t`Select supplier part`,
|
placeholder: t`Select supplier part`,
|
||||||
required: true,
|
required: true,
|
||||||
|
autoFill: true,
|
||||||
value: record.supplier_part?.pk,
|
value: record.supplier_part?.pk,
|
||||||
onValueChange: (value, instance) => {
|
onValueChange: (value, instance) => {
|
||||||
onSelectSupplierPart(record.part.pk, instance);
|
onSelectSupplierPart(record.part.pk, instance);
|
||||||
@@ -312,6 +316,12 @@ function SelectPartsStep({
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Expand>
|
</Expand>
|
||||||
|
<CopyButton
|
||||||
|
disabled={!record.supplier_part?.pk}
|
||||||
|
value={record.supplier_part?.SKU}
|
||||||
|
tooltipPosition='top-end'
|
||||||
|
tooltip={t`Copy supplier part number`}
|
||||||
|
/>
|
||||||
<AddItemButton
|
<AddItemButton
|
||||||
tooltip={t`New supplier part`}
|
tooltip={t`New supplier part`}
|
||||||
tooltipAlignment='top-end'
|
tooltipAlignment='top-end'
|
||||||
|
|||||||
@@ -107,8 +107,8 @@ export function usePurchaseOrderLineItemFields({
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
quantity: {},
|
|
||||||
reference: {},
|
reference: {},
|
||||||
|
quantity: {},
|
||||||
purchase_price: {
|
purchase_price: {
|
||||||
icon: <IconCurrencyDollar />,
|
icon: <IconCurrencyDollar />,
|
||||||
value: purchasePrice,
|
value: purchasePrice,
|
||||||
|
|||||||
@@ -190,7 +190,7 @@ export default function BuildLineTable({
|
|||||||
{
|
{
|
||||||
name: 'available',
|
name: 'available',
|
||||||
label: t`Available`,
|
label: t`Available`,
|
||||||
description: t`Show items with available stock`
|
description: t`Show items with sufficient available stock`
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'consumable',
|
name: 'consumable',
|
||||||
@@ -217,6 +217,11 @@ export default function BuildLineTable({
|
|||||||
label: t`Tracked`,
|
label: t`Tracked`,
|
||||||
description: t`Show tracked lines`
|
description: t`Show tracked lines`
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'on_order',
|
||||||
|
label: t`On Order`,
|
||||||
|
description: t`Show items with stock on order`
|
||||||
|
},
|
||||||
PartCategoryFilter()
|
PartCategoryFilter()
|
||||||
];
|
];
|
||||||
}, []);
|
}, []);
|
||||||
@@ -455,6 +460,8 @@ export default function BuildLineTable({
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
accessor: 'in_production',
|
accessor: 'in_production',
|
||||||
|
sortable: true,
|
||||||
|
ordering: 'scheduled_to_build',
|
||||||
render: (record: any) => {
|
render: (record: any) => {
|
||||||
if (record.scheduled_to_build > 0) {
|
if (record.scheduled_to_build > 0) {
|
||||||
return (
|
return (
|
||||||
@@ -471,7 +478,8 @@ export default function BuildLineTable({
|
|||||||
},
|
},
|
||||||
DecimalColumn({
|
DecimalColumn({
|
||||||
accessor: 'on_order',
|
accessor: 'on_order',
|
||||||
defaultVisible: false
|
defaultVisible: false,
|
||||||
|
sortable: true
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
accessor: 'allocated',
|
accessor: 'allocated',
|
||||||
|
|||||||
@@ -263,7 +263,9 @@ test('Purchase Orders - Order Parts', async ({ browser }) => {
|
|||||||
|
|
||||||
// Select supplier part
|
// Select supplier part
|
||||||
await page.getByLabel('related-field-supplier_part').click();
|
await page.getByLabel('related-field-supplier_part').click();
|
||||||
await page.getByText('WM1731-ND').click();
|
await page
|
||||||
|
.getByRole('option', { name: 'Thumbnail DigiKey WM1731-ND' })
|
||||||
|
.click();
|
||||||
|
|
||||||
// Option to create a new supplier part
|
// Option to create a new supplier part
|
||||||
await page.getByLabel('action-button-new-supplier-part').click();
|
await page.getByLabel('action-button-new-supplier-part').click();
|
||||||
|
|||||||
Reference in New Issue
Block a user