diff --git a/src/backend/InvenTree/common/setting/system.py b/src/backend/InvenTree/common/setting/system.py index 7a1c7349f9..9616c2f359 100644 --- a/src/backend/InvenTree/common/setting/system.py +++ b/src/backend/InvenTree/common/setting/system.py @@ -1003,6 +1003,12 @@ SYSTEM_SETTINGS: dict[str, InvenTreeSettingsKeyType] = { 'validator': bool, 'after_save': reload_plugin_registry, }, + 'PROJECT_CODES_ENABLED': { + 'name': _('Enable project codes'), + 'description': _('Enable project codes for tracking projects'), + 'default': False, + 'validator': bool, + }, 'STOCKTAKE_ENABLE': { 'name': _('Stocktake Functionality'), 'description': _( diff --git a/src/frontend/src/forms/BuildForms.tsx b/src/frontend/src/forms/BuildForms.tsx index 8beffe2547..1f3c64c847 100644 --- a/src/frontend/src/forms/BuildForms.tsx +++ b/src/frontend/src/forms/BuildForms.tsx @@ -132,6 +132,10 @@ export function useBuildOrderFields({ fields.create_child_builds = {}; } + if (!globalSettings.isSet('PROJECT_CODES_ENABLED', true)) { + delete fields.project_code; + } + return fields; }, [create, destination, batchCode, globalSettings]); } diff --git a/src/frontend/src/forms/PurchaseOrderForms.tsx b/src/frontend/src/forms/PurchaseOrderForms.tsx index 50e0b2c66e..9b8415a0d6 100644 --- a/src/frontend/src/forms/PurchaseOrderForms.tsx +++ b/src/frontend/src/forms/PurchaseOrderForms.tsx @@ -147,6 +147,8 @@ export function usePurchaseOrderFields({ supplierId?: number; duplicateOrderId?: number; }): ApiFormFieldSet { + const globalSettings = useGlobalSettingsState(); + return useMemo(() => { const fields: ApiFormFieldSet = { reference: { @@ -217,8 +219,12 @@ export function usePurchaseOrderFields({ }; } + if (!globalSettings.isSet('PROJECT_CODES_ENABLED', true)) { + delete fields.project_code; + } + return fields; - }, [duplicateOrderId, supplierId]); + }, [duplicateOrderId, supplierId, globalSettings]); } /** diff --git a/src/frontend/src/forms/ReturnOrderForms.tsx b/src/frontend/src/forms/ReturnOrderForms.tsx index 80d0d1188c..91fe3acd6c 100644 --- a/src/frontend/src/forms/ReturnOrderForms.tsx +++ b/src/frontend/src/forms/ReturnOrderForms.tsx @@ -15,6 +15,7 @@ import { ApiEndpoints } from '../enums/ApiEndpoints'; import { ModelType } from '../enums/ModelType'; import { useCreateApiFormModal } from '../hooks/UseForm'; import { apiUrl } from '../states/ApiState'; +import { useGlobalSettingsState } from '../states/SettingsState'; import { StatusFilterOptions } from '../tables/Filter'; export function useReturnOrderFields({ @@ -22,6 +23,8 @@ export function useReturnOrderFields({ }: { duplicateOrderId?: number; }): ApiFormFieldSet { + const globalSettings = useGlobalSettingsState(); + return useMemo(() => { const fields: ApiFormFieldSet = { reference: {}, @@ -82,8 +85,12 @@ export function useReturnOrderFields({ }; } + if (!globalSettings.isSet('PROJECT_CODES_ENABLED', true)) { + delete fields.project_code; + } + return fields; - }, [duplicateOrderId]); + }, [duplicateOrderId, globalSettings]); } export function useReturnOrderLineItemFields({ diff --git a/src/frontend/src/forms/SalesOrderForms.tsx b/src/frontend/src/forms/SalesOrderForms.tsx index 72d986a025..c191357dda 100644 --- a/src/frontend/src/forms/SalesOrderForms.tsx +++ b/src/frontend/src/forms/SalesOrderForms.tsx @@ -16,6 +16,7 @@ import { ApiEndpoints } from '../enums/ApiEndpoints'; import { ModelType } from '../enums/ModelType'; import { useCreateApiFormModal } from '../hooks/UseForm'; import { apiUrl } from '../states/ApiState'; +import { useGlobalSettingsState } from '../states/SettingsState'; import { PartColumn } from '../tables/ColumnRenderers'; export function useSalesOrderFields({ @@ -23,6 +24,8 @@ export function useSalesOrderFields({ }: { duplicateOrderId?: number; }): ApiFormFieldSet { + const globalSettings = useGlobalSettingsState(); + return useMemo(() => { const fields: ApiFormFieldSet = { reference: {}, @@ -76,8 +79,12 @@ export function useSalesOrderFields({ }; } + if (!globalSettings.isSet('PROJECT_CODES_ENABLED', true)) { + delete fields.project_code; + } + return fields; - }, [duplicateOrderId]); + }, [duplicateOrderId, globalSettings]); } export function useSalesOrderLineItemFields({ diff --git a/src/frontend/src/pages/Index/Settings/AdminCenter/Index.tsx b/src/frontend/src/pages/Index/Settings/AdminCenter/Index.tsx index c8d81c1b06..639737c181 100644 --- a/src/frontend/src/pages/Index/Settings/AdminCenter/Index.tsx +++ b/src/frontend/src/pages/Index/Settings/AdminCenter/Index.tsx @@ -26,6 +26,7 @@ import PageTitle from '../../../../components/nav/PageTitle'; import { SettingsHeader } from '../../../../components/nav/SettingsHeader'; import type { PanelType } from '../../../../components/panels/Panel'; import { PanelGroup } from '../../../../components/panels/PanelGroup'; +import { GlobalSettingList } from '../../../../components/settings/SettingList'; import { Loadable } from '../../../../functions/loading'; import { useUserState } from '../../../../states/UserState'; @@ -144,6 +145,7 @@ export default function AdminCenter() { icon: , content: ( + ) diff --git a/src/frontend/src/tables/ColumnRenderers.tsx b/src/frontend/src/tables/ColumnRenderers.tsx index d01d62f8ef..393ba8df39 100644 --- a/src/frontend/src/tables/ColumnRenderers.tsx +++ b/src/frontend/src/tables/ColumnRenderers.tsx @@ -14,6 +14,7 @@ import { formatCurrency, formatDate } from '../defaults/formatters'; import type { ModelType } from '../enums/ModelType'; import { resolveItem } from '../functions/conversion'; import { cancelEvent } from '../functions/events'; +import { useGlobalSettingsState } from '../states/SettingsState'; import type { TableColumn, TableColumnProps } from './Column'; import { ProjectCodeHoverCard } from './TableHoverCard'; @@ -161,11 +162,15 @@ export function LineItemsProgressColumn(): TableColumn { } export function ProjectCodeColumn(props: TableColumnProps): TableColumn { + const globalSettings = useGlobalSettingsState.getState(); + const enabled = globalSettings.isSet('PROJECT_CODES_ENABLED', true); + return { accessor: 'project_code', ordering: 'project_code', sortable: true, title: t`Project Code`, + hidden: !enabled, render: (record: any) => { const project_code = resolveItem( record, diff --git a/src/frontend/src/tables/Filter.tsx b/src/frontend/src/tables/Filter.tsx index dbeca42138..fd8bce2856 100644 --- a/src/frontend/src/tables/Filter.tsx +++ b/src/frontend/src/tables/Filter.tsx @@ -5,6 +5,7 @@ import type { StatusCodeListInterface } from '../components/render/StatusRenderer'; import type { ModelType } from '../enums/ModelType'; +import { useGlobalSettingsState } from '../states/SettingsState'; import { type StatusLookup, useGlobalStatusState } from '../states/StatusState'; /** @@ -28,9 +29,16 @@ export type TableFilterType = 'boolean' | 'choice' | 'date' | 'text'; /** * Interface for the table filter type. Provides a number of options for selecting filter value: * + * name: The name of the filter (used for query string) + * label: The label to display in the UI (human readable) + * description: A description of the filter (human readable) + * type: The type of filter (see TableFilterType) * choices: A list of TableFilterChoice objects * choiceFunction: A function which returns a list of TableFilterChoice objects - * statusType: A ModelType which is used to generate a list of status codes + * defaultValue: The default value for the filter + * value: The current value of the filter + * displayValue: The current display value of the filter + * active: Whether the filter is active (false = hidden, not used) */ export type TableFilter = { name: string; @@ -198,11 +206,15 @@ export function CompletedAfterFilter(): TableFilter { } export function HasProjectCodeFilter(): TableFilter { + const globalSettings = useGlobalSettingsState.getState(); + const enabled = globalSettings.isSet('PROJECT_CODES_ENABLED', true); + return { name: 'has_project_code', type: 'boolean', label: t`Has Project Code`, - description: t`Show orders with an assigned project code` + description: t`Show orders with an assigned project code`, + active: enabled }; } @@ -220,10 +232,14 @@ export function OrderStatusFilter({ export function ProjectCodeFilter({ choices }: { choices: TableFilterChoice[] }): TableFilter { + const globalSettings = useGlobalSettingsState.getState(); + const enabled = globalSettings.isSet('PROJECT_CODES_ENABLED', true); + return { name: 'project_code', label: t`Project Code`, description: t`Filter by project code`, + active: enabled, choices: choices }; }