diff --git a/CHANGELOG.md b/CHANGELOG.md
index 410d9a6054..4bea76d17c 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -13,6 +13,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Added
+- [#12250](https://github.com/inventree/InvenTree/pull/12250) adds "active" field to the ProjectCode model and API endpoints
+
### Changed
### Removed
diff --git a/src/backend/InvenTree/InvenTree/api_version.py b/src/backend/InvenTree/InvenTree/api_version.py
index 1bd9877491..b34c1ef5c5 100644
--- a/src/backend/InvenTree/InvenTree/api_version.py
+++ b/src/backend/InvenTree/InvenTree/api_version.py
@@ -1,11 +1,14 @@
"""InvenTree API version information."""
# InvenTree API version
-INVENTREE_API_VERSION = 512
+INVENTREE_API_VERSION = 513
"""Increment this API version number whenever there is a significant change to the API that any clients need to know about."""
INVENTREE_API_TEXT = """
+v513 -> 2026-06-25 : https://github.com/inventree/InvenTree/pull/12250
+ - Adds "active" field to the ProjectCode model and API endpoints
+
v512 -> 2026-06-20 : https://github.com/inventree/InvenTree/pull/12022
- Adds optional "merge" field to each item in the Stock Transfer API endpoint
- When merge is enabled, transferred stock is combined into compatible existing stock at the destination
diff --git a/src/backend/InvenTree/common/admin.py b/src/backend/InvenTree/common/admin.py
index e35d269f0b..44ac152760 100644
--- a/src/backend/InvenTree/common/admin.py
+++ b/src/backend/InvenTree/common/admin.py
@@ -115,7 +115,8 @@ class BarcodeScanResultAdmin(admin.ModelAdmin):
class ProjectCodeAdmin(admin.ModelAdmin):
"""Admin settings for ProjectCode."""
- list_display = ('code', 'description')
+ list_display = ('code', 'description', 'active')
+ list_filter = ('active',)
search_fields = ('code', 'description')
diff --git a/src/backend/InvenTree/common/api.py b/src/backend/InvenTree/common/api.py
index f2bec5e94b..f2a1a4c636 100644
--- a/src/backend/InvenTree/common/api.py
+++ b/src/backend/InvenTree/common/api.py
@@ -491,7 +491,7 @@ class ProjectCodeList(DataExportViewMixin, ListCreateAPI):
filter_backends = SEARCH_ORDER_FILTER
ordering_fields = ['code']
-
+ filterset_fields = ['active']
search_fields = ['code', 'description']
diff --git a/src/backend/InvenTree/common/migrations/0045_projectcode_active.py b/src/backend/InvenTree/common/migrations/0045_projectcode_active.py
new file mode 100644
index 0000000000..c0a8461972
--- /dev/null
+++ b/src/backend/InvenTree/common/migrations/0045_projectcode_active.py
@@ -0,0 +1,22 @@
+# Generated by Django 5.2.15 on 2026-06-25 03:13
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ("common", "0044_notificationmessage_charfield_pk"),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name="projectcode",
+ name="active",
+ field=models.BooleanField(
+ default=True,
+ help_text="Is this project code active?",
+ verbose_name="Active",
+ ),
+ ),
+ ]
diff --git a/src/backend/InvenTree/common/models.py b/src/backend/InvenTree/common/models.py
index 3e903ac9d2..b07dd08eeb 100644
--- a/src/backend/InvenTree/common/models.py
+++ b/src/backend/InvenTree/common/models.py
@@ -181,6 +181,12 @@ class ProjectCode(InvenTree.models.InvenTreeMetadataModel):
help_text=_('Project description'),
)
+ active = models.BooleanField(
+ default=True,
+ verbose_name=_('Active'),
+ help_text=_('Is this project code active?'),
+ )
+
responsible = models.ForeignKey(
users.models.Owner,
on_delete=models.SET_NULL,
diff --git a/src/backend/InvenTree/common/serializers.py b/src/backend/InvenTree/common/serializers.py
index 3c0ef9e859..f37e46e594 100644
--- a/src/backend/InvenTree/common/serializers.py
+++ b/src/backend/InvenTree/common/serializers.py
@@ -417,7 +417,14 @@ class ProjectCodeSerializer(DataImportExportSerializerMixin, InvenTreeModelSeria
"""Meta options for ProjectCodeSerializer."""
model = common_models.ProjectCode
- fields = ['pk', 'code', 'description', 'responsible', 'responsible_detail']
+ fields = [
+ 'pk',
+ 'code',
+ 'description',
+ 'active',
+ 'responsible',
+ 'responsible_detail',
+ ]
responsible_detail = OwnerSerializer(
source='responsible', read_only=True, allow_null=True
diff --git a/src/backend/InvenTree/common/tests.py b/src/backend/InvenTree/common/tests.py
index 2bd0c41db8..6935e3b475 100644
--- a/src/backend/InvenTree/common/tests.py
+++ b/src/backend/InvenTree/common/tests.py
@@ -1752,6 +1752,22 @@ class ProjectCodesTest(InvenTreeAPITestCase):
str(response.data['code']),
)
+ def test_filter_active(self):
+ """Test that the 'active' field can be filtered via the API."""
+ # Mark one code as inactive
+ code = ProjectCode.objects.first()
+ code.active = False
+ code.save()
+
+ active_count = ProjectCode.objects.filter(active=True).count()
+ inactive_count = ProjectCode.objects.filter(active=False).count()
+
+ response = self.get(self.url, data={'active': True}, expected_code=200)
+ self.assertEqual(len(response.data), active_count)
+
+ response = self.get(self.url, data={'active': False}, expected_code=200)
+ self.assertEqual(len(response.data), inactive_count)
+
def test_write_access(self):
"""Test that non-staff users have read-only access."""
# By default user has staff access, can create a new project code
diff --git a/src/frontend/src/forms/BuildForms.tsx b/src/frontend/src/forms/BuildForms.tsx
index 3fd3acbc41..2ff3c0bd53 100644
--- a/src/frontend/src/forms/BuildForms.tsx
+++ b/src/frontend/src/forms/BuildForms.tsx
@@ -5,7 +5,6 @@ import {
IconCircleCheck,
IconInfoCircle,
IconLink,
- IconList,
IconSitemap,
IconTruckDelivery,
IconUsersGroup
@@ -36,7 +35,7 @@ import {
} from '../hooks/UseGenerator';
import { useGlobalSettingsState } from '../states/SettingsStates';
import { RenderPartColumn } from '../tables/ColumnRenderers';
-import { TagsField } from './CommonFields';
+import { ProjectCodeField, TagsField } from './CommonFields';
/**
* Field set for BuildOrder forms
@@ -93,9 +92,7 @@ export function useBuildOrderFields({
},
title: {},
quantity: {},
- project_code: {
- icon:
- },
+ project_code: ProjectCodeField(),
priority: {},
parent: {
icon: ,
diff --git a/src/frontend/src/forms/CommonFields.tsx b/src/frontend/src/forms/CommonFields.tsx
index 9fcd5fd25b..07f16e0bb9 100644
--- a/src/frontend/src/forms/CommonFields.tsx
+++ b/src/frontend/src/forms/CommonFields.tsx
@@ -1,5 +1,6 @@
import type { ApiFormFieldType } from '@lib/types/Forms';
import { t } from '@lingui/core/macro';
+import { IconList } from '@tabler/icons-react';
export function TagsField({
label,
@@ -17,3 +18,14 @@ export function TagsField({
placeholder: placeholder ?? t`Select tags`
};
}
+
+export function ProjectCodeField(): ApiFormFieldType {
+ return {
+ filters: {
+ active: true
+ },
+ label: t`Project Code`,
+ description: t`Select project code for this item`,
+ icon:
+ };
+}
diff --git a/src/frontend/src/forms/CommonForms.tsx b/src/frontend/src/forms/CommonForms.tsx
index fc3ad49135..3bd64bc0d0 100644
--- a/src/frontend/src/forms/CommonForms.tsx
+++ b/src/frontend/src/forms/CommonForms.tsx
@@ -5,7 +5,6 @@ import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
import { ModelType } from '@lib/enums/ModelType';
import { apiUrl } from '@lib/functions/Api';
import type { ApiFormFieldSet, ApiFormFieldType } from '@lib/types/Forms';
-import { t } from '@lingui/core/macro';
import type {
StatusCodeInterface,
StatusCodeListInterface
@@ -13,6 +12,7 @@ import type {
import { useApi } from '../contexts/ApiContext';
import { useGlobalStatusState } from '../states/GlobalStatusState';
import { useUserState } from '../states/UserState';
+import { ProjectCodeField } from './CommonFields';
export function projectCodeFields(): ApiFormFieldSet {
return {
@@ -20,7 +20,8 @@ export function projectCodeFields(): ApiFormFieldSet {
description: {},
responsible: {
icon:
- }
+ },
+ active: {}
};
}
@@ -90,9 +91,7 @@ export function extraLineItemFields(): ApiFormFieldSet {
quantity: {},
price: {},
price_currency: {},
- project_code: {
- description: t`Select project code for this line item`
- },
+ project_code: ProjectCodeField(),
notes: {},
link: {}
};
diff --git a/src/frontend/src/forms/PurchaseOrderForms.tsx b/src/frontend/src/forms/PurchaseOrderForms.tsx
index 4faf5756ad..3dce873eb6 100644
--- a/src/frontend/src/forms/PurchaseOrderForms.tsx
+++ b/src/frontend/src/forms/PurchaseOrderForms.tsx
@@ -20,7 +20,6 @@ import {
IconHash,
IconInfoCircle,
IconLink,
- IconList,
IconNotes,
IconSitemap,
IconUser,
@@ -57,7 +56,7 @@ import {
useSerialNumberGenerator
} from '../hooks/UseGenerator';
import { useGlobalSettingsState } from '../states/SettingsStates';
-import { TagsField } from './CommonFields';
+import { ProjectCodeField, TagsField } from './CommonFields';
/*
* Construct a set of fields for creating / editing a PurchaseOrderLineItem instance
*/
@@ -191,9 +190,7 @@ export function usePurchaseOrderLineItemFields({
value: autoPricing,
onValueChange: setAutoPricing
},
- project_code: {
- description: t`Select project code for this line item`
- },
+ project_code: ProjectCodeField(),
target_date: {
icon:
},
@@ -271,9 +268,7 @@ export function usePurchaseOrderFields({
}
},
supplier_reference: {},
- project_code: {
- icon:
- },
+ project_code: ProjectCodeField(),
order_currency: {
icon:
},
diff --git a/src/frontend/src/forms/ReturnOrderForms.tsx b/src/frontend/src/forms/ReturnOrderForms.tsx
index ea919f5da7..3377ff1f22 100644
--- a/src/frontend/src/forms/ReturnOrderForms.tsx
+++ b/src/frontend/src/forms/ReturnOrderForms.tsx
@@ -23,7 +23,7 @@ import { Thumbnail } from '../components/images/Thumbnail';
import { useCreateApiFormModal } from '../hooks/UseForm';
import { useGlobalSettingsState } from '../states/SettingsStates';
import { StatusFilterOptions } from '../tables/Filter';
-import { TagsField } from './CommonFields';
+import { ProjectCodeField, TagsField } from './CommonFields';
export function useReturnOrderFields({
duplicateOrderId
@@ -44,7 +44,7 @@ export function useReturnOrderFields({
}
},
customer_reference: {},
- project_code: {},
+ project_code: ProjectCodeField(),
order_currency: {},
start_date: {
icon:
@@ -138,9 +138,7 @@ export function useReturnOrderLineItemFields({
},
price: {},
price_currency: {},
- project_code: {
- description: t`Select project code for this line item`
- },
+ project_code: ProjectCodeField(),
target_date: {},
notes: {},
link: {}
diff --git a/src/frontend/src/forms/SalesOrderForms.tsx b/src/frontend/src/forms/SalesOrderForms.tsx
index 125ca7f894..a863a51852 100644
--- a/src/frontend/src/forms/SalesOrderForms.tsx
+++ b/src/frontend/src/forms/SalesOrderForms.tsx
@@ -31,7 +31,7 @@ import { useCreateApiFormModal, useEditApiFormModal } from '../hooks/UseForm';
import { useGlobalSettingsState } from '../states/SettingsStates';
import { useUserState } from '../states/UserState';
import { RenderPartColumn } from '../tables/ColumnRenderers';
-import { TagsField } from './CommonFields';
+import { ProjectCodeField, TagsField } from './CommonFields';
export function useSalesOrderFields({
duplicateOrderId
@@ -57,7 +57,7 @@ export function useSalesOrderFields({
}
},
customer_reference: {},
- project_code: {},
+ project_code: ProjectCodeField(),
order_currency: {},
start_date: {
icon:
@@ -194,9 +194,7 @@ export function useSalesOrderLineItemFields({
value: partCurrency,
onValueChange: setPartCurrency
},
- project_code: {
- description: t`Select project code for this line item`
- },
+ project_code: ProjectCodeField(),
target_date: {},
notes: {},
link: {}
diff --git a/src/frontend/src/forms/TransferOrderForms.tsx b/src/frontend/src/forms/TransferOrderForms.tsx
index 3935d89b92..638028603d 100644
--- a/src/frontend/src/forms/TransferOrderForms.tsx
+++ b/src/frontend/src/forms/TransferOrderForms.tsx
@@ -10,7 +10,7 @@ import type { TableFieldRowProps } from '../components/forms/fields/TableField';
import { useCreateApiFormModal } from '../hooks/UseForm';
import { useGlobalSettingsState } from '../states/SettingsStates';
import { RenderPartColumn } from '../tables/ColumnRenderers';
-import { TagsField } from './CommonFields';
+import { ProjectCodeField, TagsField } from './CommonFields';
export function useTransferOrderFields({
duplicateOrderId
@@ -23,7 +23,7 @@ export function useTransferOrderFields({
const fields: ApiFormFieldSet = {
reference: {},
description: {},
- project_code: {},
+ project_code: ProjectCodeField(),
start_date: {
icon:
},
@@ -91,9 +91,7 @@ export function useTransferOrderLineItemFields({
},
reference: {},
quantity: {},
- project_code: {
- description: t`Select project code for this line item`
- },
+ project_code: ProjectCodeField(),
target_date: {},
notes: {},
link: {}
diff --git a/src/frontend/src/tables/settings/ProjectCodeTable.tsx b/src/frontend/src/tables/settings/ProjectCodeTable.tsx
index d6cdddf9e8..e20e3210ed 100644
--- a/src/frontend/src/tables/settings/ProjectCodeTable.tsx
+++ b/src/frontend/src/tables/settings/ProjectCodeTable.tsx
@@ -11,6 +11,7 @@ import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
import { UserRoles } from '@lib/enums/Roles';
import { apiUrl } from '@lib/functions/Api';
import useTable from '@lib/hooks/UseTable';
+import type { TableFilter } from '@lib/index';
import type { TableColumn } from '@lib/types/Tables';
import { projectCodeFields } from '../../forms/CommonForms';
import {
@@ -19,7 +20,11 @@ import {
useEditApiFormModal
} from '../../hooks/UseForm';
import { useUserState } from '../../states/UserState';
-import { DescriptionColumn, ResponsibleColumn } from '../ColumnRenderers';
+import {
+ BooleanColumn,
+ DescriptionColumn,
+ ResponsibleColumn
+} from '../ColumnRenderers';
import { InvenTreeTable } from '../InvenTreeTable';
/**
@@ -37,6 +42,9 @@ export default function ProjectCodeTable() {
sortable: true
},
DescriptionColumn({}),
+ BooleanColumn({
+ accessor: 'active'
+ }),
ResponsibleColumn({})
];
}, []);
@@ -89,6 +97,17 @@ export default function ProjectCodeTable() {
[user]
);
+ const tableFilters: TableFilter[] = useMemo(() => {
+ return [
+ {
+ name: 'active',
+ label: t`Active`,
+ description: t`Show active items`,
+ type: 'boolean'
+ }
+ ];
+ }, []);
+
const tableActions = useMemo(() => {
return [