2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-10-24 01:47:39 +00:00

Merge branch 'master' into filtered-testing

This commit is contained in:
Matthias Mair
2025-10-17 08:58:03 +02:00
committed by GitHub
35 changed files with 194 additions and 59 deletions

View File

@@ -13,6 +13,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Added much more detailed status information for machines to the API endpoint (including backend and frontend changes) in [#10381](https://github.com/inventree/InvenTree/pull/10381) - Added much more detailed status information for machines to the API endpoint (including backend and frontend changes) in [#10381](https://github.com/inventree/InvenTree/pull/10381)
- Added ability to partially complete and partially scrap build outputs in [#10499](https://github.com/inventree/InvenTree/pull/10499) - Added ability to partially complete and partially scrap build outputs in [#10499](https://github.com/inventree/InvenTree/pull/10499)
- Added support for Redis ACL user-based authentication in [#10551](https://github.com/inventree/InvenTree/pull/10551) - Added support for Redis ACL user-based authentication in [#10551](https://github.com/inventree/InvenTree/pull/10551)
- Expose stock adjustment forms to the UI plugin context in [#10584](https://github.com/inventree/InvenTree/pull/10584)
- Allow stock adjustments for "in production" items in [#10600](https://github.com/inventree/InvenTree/pull/10600)
### Changed ### Changed

View File

@@ -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

View File

@@ -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),

View File

@@ -1743,7 +1743,6 @@ class StockItem(
self.belongs_to is None, # Not installed inside another StockItem self.belongs_to is None, # Not installed inside another StockItem
self.customer is None, # Not assigned to a customer self.customer is None, # Not assigned to a customer
self.consumed_by is None, # Not consumed by a build self.consumed_by is None, # Not consumed by a build
not self.is_building, # Not part of an active build
]) ])
@property @property
@@ -2221,7 +2220,6 @@ class StockItem(
- The new item will have a different StockItem ID, while this will remain the same. - The new item will have a different StockItem ID, while this will remain the same.
""" """
# Run initial checks to test if the stock item can actually be "split" # Run initial checks to test if the stock item can actually be "split"
allow_production = kwargs.get('allow_production', False) allow_production = kwargs.get('allow_production', False)
# Cannot split a stock item which is in production # Cannot split a stock item which is in production
@@ -2346,7 +2344,9 @@ class StockItem(
'STOCK_ALLOW_OUT_OF_STOCK_TRANSFER', backup_value=False, cache=False 'STOCK_ALLOW_OUT_OF_STOCK_TRANSFER', backup_value=False, cache=False
) )
if not allow_out_of_stock_transfer and not self.is_in_stock(check_status=False): if not allow_out_of_stock_transfer and not self.is_in_stock(
check_status=False, check_in_production=False
):
raise ValidationError(_('StockItem cannot be moved as it is not in stock')) raise ValidationError(_('StockItem cannot be moved as it is not in stock'))
if quantity <= 0: if quantity <= 0:
@@ -2362,7 +2362,7 @@ class StockItem(
kwargs['notes'] = notes kwargs['notes'] = notes
# Split the existing StockItem in two # Split the existing StockItem in two
self.splitStock(quantity, location, user, **kwargs) self.splitStock(quantity, location, user, allow_production=True, **kwargs)
return True return True

View File

@@ -1554,7 +1554,7 @@ class StockAdjustmentItemSerializer(serializers.Serializer):
) )
if not allow_out_of_stock_transfer and not stock_item.is_in_stock( if not allow_out_of_stock_transfer and not stock_item.is_in_stock(
check_status=False, check_quantity=False check_status=False, check_quantity=False, check_in_production=False
): ):
raise ValidationError(_('Stock item is not in stock')) raise ValidationError(_('Stock item is not in stock'))
elif self.require_in_stock == False: elif self.require_in_stock == False:

View File

@@ -2,6 +2,14 @@
This file contains historical changelog information for the InvenTree UI components library. This file contains historical changelog information for the InvenTree UI components library.
### 0.7.0 - October 2025
Exposes stock adjustment forms to plugins, allowing plugins to adjust stock adjustments using the common InvenTree UI form components.
### 0.6.0 - September 2025
Updated underlying Mantine library versions.
### 0.5.0 - August 2025 ### 0.5.0 - August 2025
This release updates the base `react` major version from `18.3.1` to `19.1.1`. This change may introduce breaking changes for plugins that rely on the InvenTree UI components library (plugin developers should test their plugins against this new version). This release updates the base `react` major version from `18.3.1` to `19.1.1`. This change may introduce breaking changes for plugins that rely on the InvenTree UI components library (plugin developers should test their plugins against this new version).

View File

@@ -12,7 +12,12 @@ export { ModelType } from './enums/ModelType';
export type { ModelDict } from './enums/ModelInformation'; export type { ModelDict } from './enums/ModelInformation';
export { UserRoles, UserPermissions } from './enums/Roles'; export { UserRoles, UserPermissions } from './enums/Roles';
export type { InvenTreePluginContext } from './types/Plugins'; export type {
InvenTreePluginContext,
InvenTreeFormsContext,
PluginVersion,
StockAdjustmentFormsContext
} from './types/Plugins';
export type { RowAction, RowViewProps } from './types/Tables'; export type { RowAction, RowViewProps } from './types/Tables';
export type { export type {
@@ -25,6 +30,11 @@ export type {
BulkEditApiFormModalProps BulkEditApiFormModalProps
} from './types/Forms'; } from './types/Forms';
export type {
UseModalProps,
UseModalReturn
} from './types/Modals';
// Common utility functions // Common utility functions
export { apiUrl } from './functions/Api'; export { apiUrl } from './functions/Api';
export { export {

View File

@@ -191,3 +191,11 @@ export interface ApiFormModalProps extends ApiFormProps {
export interface BulkEditApiFormModalProps extends ApiFormModalProps { export interface BulkEditApiFormModalProps extends ApiFormModalProps {
items: number[]; items: number[];
} }
export type StockOperationProps = {
items?: any[];
pk?: number;
filters?: any;
model: ModelType.stockitem | 'location' | ModelType.part;
refresh: () => void;
};

View File

@@ -5,7 +5,11 @@ import type { AxiosInstance } from 'axios';
import type { NavigateFunction } from 'react-router-dom'; import type { NavigateFunction } from 'react-router-dom';
import type { ModelDict } from '../enums/ModelInformation'; import type { ModelDict } from '../enums/ModelInformation';
import type { ModelType } from '../enums/ModelType'; import type { ModelType } from '../enums/ModelType';
import type { ApiFormModalProps, BulkEditApiFormModalProps } from './Forms'; import type {
ApiFormModalProps,
BulkEditApiFormModalProps,
StockOperationProps
} from './Forms';
import type { UseModalReturn } from './Modals'; import type { UseModalReturn } from './Modals';
import type { RenderInstanceProps } from './Rendering'; import type { RenderInstanceProps } from './Rendering';
import type { SettingsStateProps } from './Settings'; import type { SettingsStateProps } from './Settings';
@@ -24,11 +28,24 @@ export interface PluginVersion {
mantine: string; mantine: string;
} }
export type StockAdjustmentFormsContext = {
addStock: (props: StockOperationProps) => UseModalReturn;
assignStock: (props: StockOperationProps) => UseModalReturn;
changeStatus: (props: StockOperationProps) => UseModalReturn;
countStock: (props: StockOperationProps) => UseModalReturn;
deleteStock: (props: StockOperationProps) => UseModalReturn;
mergeStock: (props: StockOperationProps) => UseModalReturn;
removeStock: (props: StockOperationProps) => UseModalReturn;
transferStock: (props: StockOperationProps) => UseModalReturn;
returnStock: (props: StockOperationProps) => UseModalReturn;
};
export type InvenTreeFormsContext = { export type InvenTreeFormsContext = {
bulkEdit: (props: BulkEditApiFormModalProps) => UseModalReturn; bulkEdit: (props: BulkEditApiFormModalProps) => UseModalReturn;
create: (props: ApiFormModalProps) => UseModalReturn; create: (props: ApiFormModalProps) => UseModalReturn;
delete: (props: ApiFormModalProps) => UseModalReturn; delete: (props: ApiFormModalProps) => UseModalReturn;
edit: (props: ApiFormModalProps) => UseModalReturn; edit: (props: ApiFormModalProps) => UseModalReturn;
stockActions: StockAdjustmentFormsContext;
}; };
/** /**

View File

@@ -1,7 +1,7 @@
{ {
"name": "@inventreedb/ui", "name": "@inventreedb/ui",
"description": "UI components for the InvenTree project", "description": "UI components for the InvenTree project",
"version": "0.6.0", "version": "0.7.0",
"private": false, "private": false,
"type": "module", "type": "module",
"license": "MIT", "license": "MIT",

View File

@@ -24,14 +24,17 @@ export function BuiltinQueryCountWidgets(): DashboardWidgetProps[] {
title: t`Subscribed Parts`, title: t`Subscribed Parts`,
description: t`Show the number of parts which you have subscribed to`, description: t`Show the number of parts which you have subscribed to`,
modelType: ModelType.part, modelType: ModelType.part,
params: { starred: true } params: { starred: true, active: true }
}), }),
QueryCountDashboardWidget({ QueryCountDashboardWidget({
label: 'sub-cat', label: 'sub-cat',
title: t`Subscribed Categories`, title: t`Subscribed Categories`,
description: t`Show the number of part categories which you have subscribed to`, description: t`Show the number of part categories which you have subscribed to`,
modelType: ModelType.partcategory, modelType: ModelType.partcategory,
params: { starred: true } params: {
starred: true,
top_level: 'none'
}
}), }),
QueryCountDashboardWidget({ QueryCountDashboardWidget({
label: 'invalid-bom', label: 'invalid-bom',

View File

@@ -18,6 +18,17 @@ import {
type InvenTreePluginContext type InvenTreePluginContext
} from '@lib/types/Plugins'; } from '@lib/types/Plugins';
import { i18n } from '@lingui/core'; import { i18n } from '@lingui/core';
import {
useAddStockItem,
useAssignStockItem,
useChangeStockStatus,
useCountStockItem,
useDeleteStockItem,
useMergeStockItem,
useRemoveStockItem,
useReturnStockItem,
useTransferStockItem
} from '../../forms/StockForms';
import { import {
useBulkEditApiFormModal, useBulkEditApiFormModal,
useCreateApiFormModal, useCreateApiFormModal,
@@ -60,7 +71,18 @@ export const useInvenTreeContext = () => {
bulkEdit: useBulkEditApiFormModal, bulkEdit: useBulkEditApiFormModal,
create: useCreateApiFormModal, create: useCreateApiFormModal,
delete: useDeleteApiFormModal, delete: useDeleteApiFormModal,
edit: useEditApiFormModal edit: useEditApiFormModal,
stockActions: {
addStock: useAddStockItem,
assignStock: useAssignStockItem,
changeStatus: useChangeStockStatus,
countStock: useCountStockItem,
deleteStock: useDeleteStockItem,
mergeStock: useMergeStockItem,
removeStock: useRemoveStockItem,
transferStock: useTransferStockItem,
returnStock: useReturnStockItem
}
} }
}; };
}, [ }, [

View File

@@ -37,7 +37,8 @@ import type {
ApiFormAdjustFilterType, ApiFormAdjustFilterType,
ApiFormFieldChoice, ApiFormFieldChoice,
ApiFormFieldSet, ApiFormFieldSet,
ApiFormModalProps ApiFormModalProps,
StockOperationProps
} from '@lib/types/Forms'; } from '@lib/types/Forms';
import { import {
TableFieldExtraRow, TableFieldExtraRow,
@@ -711,6 +712,9 @@ function stockTransferFields(items: any[]): ApiFormFieldSet {
const records = Object.fromEntries(items.map((item) => [item.pk, item])); const records = Object.fromEntries(items.map((item) => [item.pk, item]));
// Extract all location values from the items
const locations = [...new Set(items.map((item) => item.location))];
const fields: ApiFormFieldSet = { const fields: ApiFormFieldSet = {
items: { items: {
field_type: 'table', field_type: 'table',
@@ -739,6 +743,7 @@ function stockTransferFields(items: any[]): ApiFormFieldSet {
] ]
}, },
location: { location: {
value: locations.length === 1 ? locations[0] : undefined,
filters: { filters: {
structural: false structural: false
} }
@@ -1172,14 +1177,6 @@ function useStockOperationModal({
}); });
} }
export type StockOperationProps = {
items?: any[];
pk?: number;
filters?: any;
model: ModelType.stockitem | 'location' | ModelType.part;
refresh: () => void;
};
export function useAddStockItem(props: StockOperationProps) { export function useAddStockItem(props: StockOperationProps) {
return useStockOperationModal({ return useStockOperationModal({
...props, ...props,

View File

@@ -1,11 +1,11 @@
import { UserRoles } from '@lib/index'; import { UserRoles } from '@lib/index';
import type { StockOperationProps } from '@lib/types/Forms';
import type { UseModalReturn } from '@lib/types/Modals'; import type { UseModalReturn } from '@lib/types/Modals';
import { t } from '@lingui/core/macro'; import { t } from '@lingui/core/macro';
import { type ReactNode, useMemo } from 'react'; import { type ReactNode, useMemo } from 'react';
import type { ActionDropdownItem } from '../components/items/ActionDropdown'; import type { ActionDropdownItem } from '../components/items/ActionDropdown';
import { ActionDropdown } from '../components/items/ActionDropdown'; import { ActionDropdown } from '../components/items/ActionDropdown';
import { import {
type StockOperationProps,
useAddStockItem, useAddStockItem,
useAssignStockItem, useAssignStockItem,
useChangeStockStatus, useChangeStockStatus,
@@ -54,8 +54,8 @@ export function useStockAdjustActions(
// The available modals for stock adjustment actions // The available modals for stock adjustment actions
const addStock = useAddStockItem(props.formProps); const addStock = useAddStockItem(props.formProps);
const assignStock = useAssignStockItem(props.formProps); const assignStock = useAssignStockItem(props.formProps);
const countStock = useCountStockItem(props.formProps);
const changeStatus = useChangeStockStatus(props.formProps); const changeStatus = useChangeStockStatus(props.formProps);
const countStock = useCountStockItem(props.formProps);
const deleteStock = useDeleteStockItem(props.formProps); const deleteStock = useDeleteStockItem(props.formProps);
const mergeStock = useMergeStockItem(props.formProps); const mergeStock = useMergeStockItem(props.formProps);
const removeStock = useRemoveStockItem(props.formProps); const removeStock = useRemoveStockItem(props.formProps);

View File

@@ -679,6 +679,7 @@ export default function BuildDetail() {
<PrintingActions <PrintingActions
modelType={ModelType.build} modelType={ModelType.build}
items={[build.pk]} items={[build.pk]}
enableLabels
enableReports enableReports
/>, />,
<OptionsActionDropdown <OptionsActionDropdown

View File

@@ -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} />
) )
}, },
{ {

View File

@@ -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();
@@ -278,7 +294,7 @@ export default function ManufacturerPartDetail() {
> >
<Stack gap='xs'> <Stack gap='xs'>
<PageDetail <PageDetail
title={t`ManufacturerPart`} title={t`Manufacturer Part`}
subtitle={`${manufacturerPart.MPN} - ${manufacturerPart.part_detail?.name}`} subtitle={`${manufacturerPart.MPN} - ${manufacturerPart.part_detail?.name}`}
breadcrumbs={breadcrumbs} breadcrumbs={breadcrumbs}
lastCrumb={[ lastCrumb={[

View File

@@ -47,7 +47,7 @@ import { UserRoles } from '@lib/enums/Roles';
import { apiUrl } from '@lib/functions/Api'; import { apiUrl } from '@lib/functions/Api';
import { getDetailUrl } from '@lib/functions/Navigation'; import { getDetailUrl } from '@lib/functions/Navigation';
import { ActionButton } from '@lib/index'; import { ActionButton } from '@lib/index';
import type { ApiFormFieldSet } from '@lib/types/Forms'; import type { ApiFormFieldSet, StockOperationProps } from '@lib/types/Forms';
import AdminButton from '../../components/buttons/AdminButton'; import AdminButton from '../../components/buttons/AdminButton';
import { PrintingActions } from '../../components/buttons/PrintingActions'; import { PrintingActions } from '../../components/buttons/PrintingActions';
import StarredToggleButton from '../../components/buttons/StarredToggleButton'; import StarredToggleButton from '../../components/buttons/StarredToggleButton';
@@ -80,10 +80,7 @@ import OrderPartsWizard from '../../components/wizards/OrderPartsWizard';
import { useApi } from '../../contexts/ApiContext'; import { useApi } from '../../contexts/ApiContext';
import { formatDecimal, formatPriceRange } from '../../defaults/formatters'; import { formatDecimal, formatPriceRange } from '../../defaults/formatters';
import { usePartFields } from '../../forms/PartForms'; import { usePartFields } from '../../forms/PartForms';
import { import { useFindSerialNumberForm } from '../../forms/StockForms';
type StockOperationProps,
useFindSerialNumberForm
} from '../../forms/StockForms';
import { import {
useApiFormModal, useApiFormModal,
useCreateApiFormModal, useCreateApiFormModal,

View File

@@ -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>

View File

@@ -460,6 +460,7 @@ export default function PurchaseOrderDetail() {
<PrintingActions <PrintingActions
modelType={ModelType.purchaseorder} modelType={ModelType.purchaseorder}
items={[order.pk]} items={[order.pk]}
enableLabels
enableReports enableReports
/>, />,
<OptionsActionDropdown <OptionsActionDropdown

View File

@@ -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]);

View File

@@ -458,6 +458,7 @@ export default function ReturnOrderDetail() {
modelType={ModelType.returnorder} modelType={ModelType.returnorder}
items={[order.pk]} items={[order.pk]}
enableReports enableReports
enableLabels
/>, />,
<OptionsActionDropdown <OptionsActionDropdown
tooltip={t`Order Actions`} tooltip={t`Order Actions`}

View File

@@ -516,6 +516,7 @@ export default function SalesOrderDetail() {
modelType={ModelType.salesorder} modelType={ModelType.salesorder}
items={[order.pk]} items={[order.pk]}
enableReports enableReports
enableLabels
/>, />,
<OptionsActionDropdown <OptionsActionDropdown
tooltip={t`Order Actions`} tooltip={t`Order Actions`}

View File

@@ -3,6 +3,7 @@ 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 { getDetailUrl } from '@lib/functions/Navigation'; import { getDetailUrl } from '@lib/functions/Navigation';
import type { StockOperationProps } from '@lib/types/Forms';
import { t } from '@lingui/core/macro'; import { t } from '@lingui/core/macro';
import { Group, Skeleton, Stack, Text } from '@mantine/core'; import { Group, Skeleton, Stack, Text } from '@mantine/core';
import { IconInfoCircle, IconPackages, IconSitemap } from '@tabler/icons-react'; import { IconInfoCircle, IconPackages, IconSitemap } from '@tabler/icons-react';
@@ -30,10 +31,7 @@ import { PageDetail } from '../../components/nav/PageDetail';
import type { PanelType } from '../../components/panels/Panel'; import type { PanelType } from '../../components/panels/Panel';
import { PanelGroup } from '../../components/panels/PanelGroup'; import { PanelGroup } from '../../components/panels/PanelGroup';
import LocateItemButton from '../../components/plugins/LocateItemButton'; import LocateItemButton from '../../components/plugins/LocateItemButton';
import { import { stockLocationFields } from '../../forms/StockForms';
type StockOperationProps,
stockLocationFields
} from '../../forms/StockForms';
import { InvenTreeIcon } from '../../functions/icons'; import { InvenTreeIcon } from '../../functions/icons';
import { import {
useDeleteApiFormModal, useDeleteApiFormModal,

View File

@@ -33,6 +33,7 @@ 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 { getDetailUrl } from '@lib/functions/Navigation'; import { getDetailUrl } from '@lib/functions/Navigation';
import type { StockOperationProps } from '@lib/types/Forms';
import { notifications } from '@mantine/notifications'; import { notifications } from '@mantine/notifications';
import { useBarcodeScanDialog } from '../../components/barcodes/BarcodeScanDialog'; import { useBarcodeScanDialog } from '../../components/barcodes/BarcodeScanDialog';
import AdminButton from '../../components/buttons/AdminButton'; import AdminButton from '../../components/buttons/AdminButton';
@@ -66,7 +67,6 @@ import OrderPartsWizard from '../../components/wizards/OrderPartsWizard';
import { useApi } from '../../contexts/ApiContext'; import { useApi } from '../../contexts/ApiContext';
import { formatCurrency, formatDecimal } from '../../defaults/formatters'; import { formatCurrency, formatDecimal } from '../../defaults/formatters';
import { import {
type StockOperationProps,
useFindSerialNumberForm, useFindSerialNumberForm,
useStockFields, useStockFields,
useStockItemSerializeFields useStockItemSerializeFields

View File

@@ -250,7 +250,10 @@ export default function InvenTreeTableHeader({
<HoverCard <HoverCard
position='bottom-end' position='bottom-end'
withinPortal={true} withinPortal={true}
disabled={!tableState.filterSet.activeFilters?.length} disabled={
hasCustomFilters ||
!tableState.filterSet.activeFilters?.length
}
> >
<HoverCard.Target> <HoverCard.Target>
<Tooltip <Tooltip

View File

@@ -12,10 +12,10 @@ import { UserRoles } from '@lib/enums/Roles';
import { apiUrl } from '@lib/functions/Api'; import { apiUrl } from '@lib/functions/Api';
import { ActionButton } from '@lib/index'; import { ActionButton } from '@lib/index';
import type { TableFilter } from '@lib/types/Filters'; import type { TableFilter } from '@lib/types/Filters';
import type { StockOperationProps } from '@lib/types/Forms';
import type { TableColumn } from '@lib/types/Tables'; import type { TableColumn } from '@lib/types/Tables';
import { IconCircleDashedCheck } from '@tabler/icons-react'; import { IconCircleDashedCheck } from '@tabler/icons-react';
import { useConsumeBuildItemsForm } from '../../forms/BuildForms'; import { useConsumeBuildItemsForm } from '../../forms/BuildForms';
import type { StockOperationProps } from '../../forms/StockForms';
import { import {
useDeleteApiFormModal, useDeleteApiFormModal,
useEditApiFormModal useEditApiFormModal

View File

@@ -248,6 +248,7 @@ export function BuildOrderTable({
modelType: ModelType.build, modelType: ModelType.build,
enableSelection: true, enableSelection: true,
enableReports: true, enableReports: true,
enableLabels: true,
enableDownload: true enableDownload: true
}} }}
/> />

View File

@@ -33,6 +33,7 @@ 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 { TableFilter } from '@lib/types/Filters';
import type { StockOperationProps } from '@lib/types/Forms';
import type { TableColumn } from '@lib/types/Tables'; import type { TableColumn } from '@lib/types/Tables';
import { StylishText } from '../../components/items/StylishText'; import { StylishText } from '../../components/items/StylishText';
import { useApi } from '../../contexts/ApiContext'; import { useApi } from '../../contexts/ApiContext';
@@ -43,7 +44,6 @@ import {
useScrapBuildOutputsForm useScrapBuildOutputsForm
} from '../../forms/BuildForms'; } from '../../forms/BuildForms';
import { import {
type StockOperationProps,
useStockFields, useStockFields,
useStockItemSerializeFields useStockItemSerializeFields
} from '../../forms/StockForms'; } from '../../forms/StockForms';

View File

@@ -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
}} }}
/> />

View File

@@ -190,7 +190,8 @@ export function PurchaseOrderTable({
modelType: ModelType.purchaseorder, modelType: ModelType.purchaseorder,
enableSelection: true, enableSelection: true,
enableDownload: true, enableDownload: true,
enableReports: true enableReports: true,
enableLabels: true
}} }}
/> />
</> </>

View File

@@ -189,7 +189,8 @@ export function ReturnOrderTable({
modelType: ModelType.returnorder, modelType: ModelType.returnorder,
enableSelection: true, enableSelection: true,
enableDownload: true, enableDownload: true,
enableReports: true enableReports: true,
enableLabels: true
}} }}
/> />
</> </>

View File

@@ -12,11 +12,11 @@ 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 { TableFilter } from '@lib/types/Filters';
import type { StockOperationProps } from '@lib/types/Forms';
import type { TableColumn } from '@lib/types/Tables'; import type { TableColumn } from '@lib/types/Tables';
import { IconTruckDelivery } from '@tabler/icons-react'; import { IconTruckDelivery } from '@tabler/icons-react';
import { formatDate } from '../../defaults/formatters'; import { formatDate } from '../../defaults/formatters';
import { useSalesOrderAllocationFields } from '../../forms/SalesOrderForms'; import { useSalesOrderAllocationFields } from '../../forms/SalesOrderForms';
import type { StockOperationProps } from '../../forms/StockForms';
import { import {
useBulkEditApiFormModal, useBulkEditApiFormModal,
useDeleteApiFormModal, useDeleteApiFormModal,

View File

@@ -201,7 +201,8 @@ export function SalesOrderTable({
modelType: ModelType.salesorder, modelType: ModelType.salesorder,
enableSelection: true, enableSelection: true,
enableDownload: true, enableDownload: true,
enableReports: true enableReports: true,
enableLabels: true
}} }}
/> />
</> </>

View File

@@ -11,6 +11,7 @@ import { UserRoles } from '@lib/enums/Roles';
import { apiUrl } from '@lib/functions/Api'; import { apiUrl } from '@lib/functions/Api';
import { getDetailUrl } from '@lib/functions/Navigation'; import { getDetailUrl } from '@lib/functions/Navigation';
import type { TableFilter } from '@lib/types/Filters'; import type { TableFilter } from '@lib/types/Filters';
import type { StockOperationProps } from '@lib/types/Forms';
import type { TableColumn } from '@lib/types/Tables'; import type { TableColumn } from '@lib/types/Tables';
import OrderPartsWizard from '../../components/wizards/OrderPartsWizard'; import OrderPartsWizard from '../../components/wizards/OrderPartsWizard';
import { import {
@@ -18,10 +19,7 @@ import {
formatDecimal, formatDecimal,
formatPriceRange formatPriceRange
} from '../../defaults/formatters'; } from '../../defaults/formatters';
import { import { useStockFields } from '../../forms/StockForms';
type StockOperationProps,
useStockFields
} from '../../forms/StockForms';
import { InvenTreeIcon } from '../../functions/icons'; import { InvenTreeIcon } from '../../functions/icons';
import { useCreateApiFormModal } from '../../hooks/UseForm'; import { useCreateApiFormModal } from '../../hooks/UseForm';
import { useStockAdjustActions } from '../../hooks/UseStockAdjustActions'; import { useStockAdjustActions } from '../../hooks/UseStockAdjustActions';