mirror of
https://github.com/inventree/InvenTree.git
synced 2025-10-21 16:37:39 +00:00
[UI] Manufacturer part updates (#10601)
* Add filters for manufacturer parts table * Refactor <ManufacturerPartTable /> * Fix typo * Additional filter options for StockList: - Filter by ManufacturerPart ID * Stock table view for ManufacturerPart * Bump API version
This commit is contained in:
@@ -1,12 +1,15 @@
|
|||||||
"""InvenTree API version information."""
|
"""InvenTree API version information."""
|
||||||
|
|
||||||
# InvenTree API version
|
# InvenTree API version
|
||||||
INVENTREE_API_VERSION = 408
|
INVENTREE_API_VERSION = 409
|
||||||
|
|
||||||
"""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 = """
|
||||||
|
|
||||||
|
v409 -> 2025-10-17 : https://github.com/inventree/InvenTree/pull/10601
|
||||||
|
- Adds ability to filter StockList API by manufacturer part ID
|
||||||
|
|
||||||
v408 -> 2025-10-13: https://github.com/inventree/InvenTree/pull/10561
|
v408 -> 2025-10-13: https://github.com/inventree/InvenTree/pull/10561
|
||||||
- Allow search of assembly fields in BOM API endpoint
|
- Allow search of assembly fields in BOM API endpoint
|
||||||
|
|
||||||
|
@@ -25,7 +25,7 @@ import InvenTree.permissions
|
|||||||
import stock.serializers as StockSerializers
|
import stock.serializers as StockSerializers
|
||||||
from build.models import Build
|
from build.models import Build
|
||||||
from build.serializers import BuildSerializer
|
from build.serializers import BuildSerializer
|
||||||
from company.models import Company, SupplierPart
|
from company.models import Company, ManufacturerPart, SupplierPart
|
||||||
from company.serializers import CompanySerializer
|
from company.serializers import CompanySerializer
|
||||||
from data_exporter.mixins import DataExportViewMixin
|
from data_exporter.mixins import DataExportViewMixin
|
||||||
from generic.states.api import StatusView
|
from generic.states.api import StatusView
|
||||||
@@ -553,6 +553,12 @@ class StockFilter(FilterSet):
|
|||||||
& Q(supplier_part__manufacturer_part__manufacturer=company)
|
& Q(supplier_part__manufacturer_part__manufacturer=company)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
manufacturer_part = rest_filters.ModelChoiceFilter(
|
||||||
|
label=_('Manufacturer Part'),
|
||||||
|
queryset=ManufacturerPart.objects.all(),
|
||||||
|
field_name='supplier_part__manufacturer_part',
|
||||||
|
)
|
||||||
|
|
||||||
supplier = rest_filters.ModelChoiceFilter(
|
supplier = rest_filters.ModelChoiceFilter(
|
||||||
label=_('Supplier'),
|
label=_('Supplier'),
|
||||||
queryset=Company.objects.filter(is_supplier=True),
|
queryset=Company.objects.filter(is_supplier=True),
|
||||||
|
@@ -197,7 +197,7 @@ export default function CompanyDetail(props: Readonly<CompanyDetailProps>) {
|
|||||||
icon: <IconBuildingWarehouse />,
|
icon: <IconBuildingWarehouse />,
|
||||||
hidden: !company?.is_manufacturer,
|
hidden: !company?.is_manufacturer,
|
||||||
content: company?.pk && (
|
content: company?.pk && (
|
||||||
<ManufacturerPartTable params={{ manufacturer: company.pk }} />
|
<ManufacturerPartTable manufacturerId={company.pk} />
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@@ -3,7 +3,8 @@ import { Grid, Skeleton, Stack } from '@mantine/core';
|
|||||||
import {
|
import {
|
||||||
IconBuildingWarehouse,
|
IconBuildingWarehouse,
|
||||||
IconInfoCircle,
|
IconInfoCircle,
|
||||||
IconList
|
IconList,
|
||||||
|
IconPackages
|
||||||
} from '@tabler/icons-react';
|
} from '@tabler/icons-react';
|
||||||
import { useMemo } from 'react';
|
import { useMemo } from 'react';
|
||||||
import { useNavigate, useParams } from 'react-router-dom';
|
import { useNavigate, useParams } from 'react-router-dom';
|
||||||
@@ -42,6 +43,7 @@ import { useInstance } from '../../hooks/UseInstance';
|
|||||||
import { useUserState } from '../../states/UserState';
|
import { useUserState } from '../../states/UserState';
|
||||||
import ManufacturerPartParameterTable from '../../tables/purchasing/ManufacturerPartParameterTable';
|
import ManufacturerPartParameterTable from '../../tables/purchasing/ManufacturerPartParameterTable';
|
||||||
import { SupplierPartTable } from '../../tables/purchasing/SupplierPartTable';
|
import { SupplierPartTable } from '../../tables/purchasing/SupplierPartTable';
|
||||||
|
import { StockItemTable } from '../../tables/stock/StockItemTable';
|
||||||
|
|
||||||
export default function ManufacturerPartDetail() {
|
export default function ManufacturerPartDetail() {
|
||||||
const { id } = useParams();
|
const { id } = useParams();
|
||||||
@@ -171,6 +173,20 @@ export default function ManufacturerPartDetail() {
|
|||||||
<Skeleton />
|
<Skeleton />
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'stock',
|
||||||
|
label: t`Received Stock`,
|
||||||
|
hidden: !user.hasViewRole(UserRoles.stock),
|
||||||
|
icon: <IconPackages />,
|
||||||
|
content: (
|
||||||
|
<StockItemTable
|
||||||
|
tableName='manufacturer-part-stock'
|
||||||
|
params={{
|
||||||
|
manufacturer_part: id
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: 'suppliers',
|
name: 'suppliers',
|
||||||
label: t`Suppliers`,
|
label: t`Suppliers`,
|
||||||
@@ -194,7 +210,7 @@ export default function ManufacturerPartDetail() {
|
|||||||
model_id: manufacturerPart?.pk
|
model_id: manufacturerPart?.pk
|
||||||
})
|
})
|
||||||
];
|
];
|
||||||
}, [manufacturerPart]);
|
}, [user, manufacturerPart]);
|
||||||
|
|
||||||
const editManufacturerPartFields = useManufacturerPartFields();
|
const editManufacturerPartFields = useManufacturerPartFields();
|
||||||
|
|
||||||
|
@@ -23,7 +23,7 @@ export default function PartSupplierDetail({
|
|||||||
<StylishText size='lg'>{t`Manufacturers`}</StylishText>
|
<StylishText size='lg'>{t`Manufacturers`}</StylishText>
|
||||||
</Accordion.Control>
|
</Accordion.Control>
|
||||||
<Accordion.Panel>
|
<Accordion.Panel>
|
||||||
<ManufacturerPartTable params={{ part: partId }} />
|
<ManufacturerPartTable partId={partId} />
|
||||||
</Accordion.Panel>
|
</Accordion.Panel>
|
||||||
</Accordion.Item>
|
</Accordion.Item>
|
||||||
</Accordion>
|
</Accordion>
|
||||||
|
@@ -108,7 +108,7 @@ export default function PurchasingIndex() {
|
|||||||
name: 'manufacturer-parts',
|
name: 'manufacturer-parts',
|
||||||
label: t`Manufacturer Parts`,
|
label: t`Manufacturer Parts`,
|
||||||
icon: <IconBuildingWarehouse />,
|
icon: <IconBuildingWarehouse />,
|
||||||
content: <ManufacturerPartTable params={{}} />
|
content: <ManufacturerPartTable />
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
}, [user, purchaseOrderView]);
|
}, [user, purchaseOrderView]);
|
||||||
|
@@ -11,6 +11,7 @@ import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
|
|||||||
import { ModelType } from '@lib/enums/ModelType';
|
import { ModelType } from '@lib/enums/ModelType';
|
||||||
import { UserRoles } from '@lib/enums/Roles';
|
import { UserRoles } from '@lib/enums/Roles';
|
||||||
import { apiUrl } from '@lib/functions/Api';
|
import { apiUrl } from '@lib/functions/Api';
|
||||||
|
import type { TableFilter } from '@lib/types/Filters';
|
||||||
import type { TableColumn } from '@lib/types/Tables';
|
import type { TableColumn } from '@lib/types/Tables';
|
||||||
import { useManufacturerPartFields } from '../../forms/CompanyForms';
|
import { useManufacturerPartFields } from '../../forms/CompanyForms';
|
||||||
import {
|
import {
|
||||||
@@ -32,9 +33,27 @@ import { InvenTreeTable } from '../InvenTreeTable';
|
|||||||
* Construct a table listing manufacturer parts
|
* Construct a table listing manufacturer parts
|
||||||
*/
|
*/
|
||||||
export function ManufacturerPartTable({
|
export function ManufacturerPartTable({
|
||||||
params
|
manufacturerId,
|
||||||
}: Readonly<{ params: any }>): ReactNode {
|
partId
|
||||||
const table = useTable('manufacturerparts');
|
}: Readonly<{
|
||||||
|
manufacturerId?: number;
|
||||||
|
partId?: number;
|
||||||
|
}>): ReactNode {
|
||||||
|
const tableId: string = useMemo(() => {
|
||||||
|
let tId = 'manufacturer-part';
|
||||||
|
|
||||||
|
if (manufacturerId) {
|
||||||
|
tId += '-manufacturer';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (partId) {
|
||||||
|
tId += '-part';
|
||||||
|
}
|
||||||
|
|
||||||
|
return tId;
|
||||||
|
}, [manufacturerId, partId]);
|
||||||
|
|
||||||
|
const table = useTable(tableId);
|
||||||
|
|
||||||
const user = useUserState();
|
const user = useUserState();
|
||||||
|
|
||||||
@@ -42,7 +61,7 @@ export function ManufacturerPartTable({
|
|||||||
const tableColumns: TableColumn[] = useMemo(() => {
|
const tableColumns: TableColumn[] = useMemo(() => {
|
||||||
return [
|
return [
|
||||||
PartColumn({
|
PartColumn({
|
||||||
switchable: 'part' in params
|
switchable: !!partId
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
accessor: 'manufacturer',
|
accessor: 'manufacturer',
|
||||||
@@ -59,7 +78,7 @@ export function ManufacturerPartTable({
|
|||||||
DescriptionColumn({}),
|
DescriptionColumn({}),
|
||||||
LinkColumn({})
|
LinkColumn({})
|
||||||
];
|
];
|
||||||
}, [params]);
|
}, [partId]);
|
||||||
|
|
||||||
const manufacturerPartFields = useManufacturerPartFields();
|
const manufacturerPartFields = useManufacturerPartFields();
|
||||||
|
|
||||||
@@ -73,8 +92,8 @@ export function ManufacturerPartTable({
|
|||||||
fields: manufacturerPartFields,
|
fields: manufacturerPartFields,
|
||||||
table: table,
|
table: table,
|
||||||
initialData: {
|
initialData: {
|
||||||
manufacturer: params?.manufacturer,
|
manufacturer: manufacturerId,
|
||||||
part: params?.part
|
part: partId
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -93,6 +112,24 @@ export function ManufacturerPartTable({
|
|||||||
table: table
|
table: table
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const tableFilters: TableFilter[] = useMemo(() => {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
name: 'part_active',
|
||||||
|
label: t`Active Part`,
|
||||||
|
description: t`Show manufacturer parts for active internal parts.`,
|
||||||
|
type: 'boolean'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'manufacturer_active',
|
||||||
|
label: t`Active Manufacturer`,
|
||||||
|
active: !manufacturerId,
|
||||||
|
description: t`Show manufacturer parts for active manufacturers.`,
|
||||||
|
type: 'boolean'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}, [manufacturerId]);
|
||||||
|
|
||||||
const tableActions = useMemo(() => {
|
const tableActions = useMemo(() => {
|
||||||
const can_add =
|
const can_add =
|
||||||
user.hasAddRole(UserRoles.purchase_order) &&
|
user.hasAddRole(UserRoles.purchase_order) &&
|
||||||
@@ -141,13 +178,15 @@ export function ManufacturerPartTable({
|
|||||||
columns={tableColumns}
|
columns={tableColumns}
|
||||||
props={{
|
props={{
|
||||||
params: {
|
params: {
|
||||||
...params,
|
part: partId,
|
||||||
|
manufacturer: manufacturerId,
|
||||||
part_detail: true,
|
part_detail: true,
|
||||||
manufacturer_detail: true
|
manufacturer_detail: true
|
||||||
},
|
},
|
||||||
enableDownload: true,
|
enableDownload: true,
|
||||||
rowActions: rowActions,
|
rowActions: rowActions,
|
||||||
tableActions: tableActions,
|
tableActions: tableActions,
|
||||||
|
tableFilters: tableFilters,
|
||||||
modelType: ModelType.manufacturerpart
|
modelType: ModelType.manufacturerpart
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
Reference in New Issue
Block a user