diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1129b2ee0d..10e13b4cab 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -24,6 +24,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- [#12900](https://github.com/Inventree/InvenTree/pull/12900) adds a UI feature `route` to the `UIMixin`, giving plugins the ability to register custom pages.
- [#12911](https://github.com/inventree/InvenTree/pull/12911) adds global setting for default receive location against purchase orders
- [#12914](https://github.com/inventree/InvenTree/pull/12914) adds the AllocateMixin, allowing plugins to customize automatic stock allocation for build orders and sales orders.
+- [#13017](https://github.com/inventree/InvenTree/pull/13017) adds "internal" companies, which represent your own organization, along with a `INVENTREE_DEFAULT_INTERNAL_COMPANY` setting. The default internal company is available to all report templates as `internal_company`.
- [#13016](https://github.com/inventree/InvenTree/pull/13016) adds a "contact" field to the SalesOrderShipment model and API endpoint.
- [#13016](https://github.com/inventree/InvenTree/pull/13016) adds "phone" and "email" fields to the Address model and API endpoint.
diff --git a/docs/docs/concepts/company.md b/docs/docs/concepts/company.md
index b99128c7fb..c26a567215 100644
--- a/docs/docs/concepts/company.md
+++ b/docs/docs/concepts/company.md
@@ -14,6 +14,31 @@ External companies are represented by the *Company* database model. Each company
!!! tip "Multi Purpose"
A company may be allocated to multiple categories, for example, a company may be both a supplier and a customer.
+### Internal Companies
+
+A company can also be marked as *internal*, meaning that it represents your own organization rather than an external business. Internal companies can have their own [contacts](#contacts) and [addresses](#addresses), just like any other company.
+
+More than one internal company can be defined - for example, if your organization operates as multiple legal entities, or from multiple sites.
+
+Internal companies are managed from the *Internal Companies* panel in the [Admin Center](../settings/admin.md). To mark an existing company as internal, edit the company and set the `is_internal` attribute to `True`.
+
+#### Default Internal Company
+
+The `INVENTREE_DEFAULT_INTERNAL_COMPANY` [global setting](../settings/global.md#server-settings) selects which internal company represents your organization by default. Only companies marked as internal can be selected.
+
+If this setting is not specified, and exactly one internal company exists, that company is used as the default.
+
+The default internal company is available to all [report and label templates](../report/context_variables.md) as the `internal_company` context variable. For example, to render your organization's name and primary address in a report header:
+
+```html
+{% raw %}
+{% if internal_company %}
+
{{ internal_company.name }}
+{{ internal_company.primary_address }}
+{% endif %}
+{% endraw %}
+```
+
### Edit Company
To edit a company, click on the {{ icon("edit", color="blue", title="Edit Company") }} icon in the actions menu. Edit the company information, and then click on Submit.
diff --git a/docs/docs/settings/global.md b/docs/docs/settings/global.md
index ee5820408a..08273b91e2 100644
--- a/docs/docs/settings/global.md
+++ b/docs/docs/settings/global.md
@@ -23,6 +23,7 @@ Configuration of basic server settings:
| ---- | ----------- | ------- | ----- |
{{ globalsetting("INVENTREE_BASE_URL") }}
{{ globalsetting("INVENTREE_COMPANY_NAME") }}
+{{ globalsetting("INVENTREE_DEFAULT_INTERNAL_COMPANY") }}
{{ globalsetting("INVENTREE_INSTANCE") }}
{{ globalsetting("INVENTREE_INSTANCE_TITLE") }}
{{ globalsetting("INVENTREE_INSTANCE_ID", default="Randomly generated value") }}
diff --git a/src/backend/InvenTree/InvenTree/api_version.py b/src/backend/InvenTree/InvenTree/api_version.py
index 4dc9a2b4d0..fc92f412d6 100644
--- a/src/backend/InvenTree/InvenTree/api_version.py
+++ b/src/backend/InvenTree/InvenTree/api_version.py
@@ -1,11 +1,16 @@
"""InvenTree API version information."""
# InvenTree API version
-INVENTREE_API_VERSION = 555
+INVENTREE_API_VERSION = 556
"""Increment this API version number whenever there is a significant change to the API that any clients need to know about."""
INVENTREE_API_TEXT = """
+v556 -> 2026-10-14 : https://github.com/inventree/InvenTree/pull/13017
+ - Adds 'is_internal' field (and filter) to the Company API endpoint
+ - Adds 'INVENTREE_DEFAULT_INTERNAL_COMPANY' global setting
+ - Exposes 'model_filters' on the global and user settings API endpoints
+
v555 -> 2026-10-14 : https://github.com/inventree/InvenTree/pull/13016
- Adds "contact" field to the SalesOrderShipment model and API endpoint
- Adds "phone" and "email" fields to the Address model and API endpoint
diff --git a/src/backend/InvenTree/common/serializers.py b/src/backend/InvenTree/common/serializers.py
index 4d198dc311..5b5cac1899 100644
--- a/src/backend/InvenTree/common/serializers.py
+++ b/src/backend/InvenTree/common/serializers.py
@@ -179,6 +179,7 @@ class GlobalSettingsSerializer(SettingsSerializer):
'units',
'choices',
'model_name',
+ 'model_filters',
'api_url',
'typ',
'read_only',
@@ -226,6 +227,7 @@ class UserSettingsSerializer(SettingsSerializer):
'units',
'choices',
'model_name',
+ 'model_filters',
'api_url',
'typ',
'confirm',
diff --git a/src/backend/InvenTree/common/setting/system.py b/src/backend/InvenTree/common/setting/system.py
index 86e694c9fe..1ae86ef800 100644
--- a/src/backend/InvenTree/common/setting/system.py
+++ b/src/backend/InvenTree/common/setting/system.py
@@ -21,6 +21,24 @@ import report.helpers
from common.setting.type import InvenTreeSettingsKeyType, SettingFlag
+def validate_internal_company(value):
+ """Validate that the provided value is empty, or references an internal company."""
+ from company.models import Company
+
+ if value in [None, '']:
+ return
+
+ try:
+ pk = int(value)
+ except (TypeError, ValueError):
+ raise ValidationError({'value': _('Invalid company')})
+
+ if not Company.objects.filter(pk=pk, is_internal=True).exists():
+ raise ValidationError({
+ 'value': _('Selected company must be marked as an internal company')
+ })
+
+
def validate_part_name_format(value):
"""Validate part name format.
@@ -255,6 +273,14 @@ SYSTEM_SETTINGS: dict[str, InvenTreeSettingsKeyType] = {
'description': _('Internal company name'),
'default': 'My company name',
},
+ 'INVENTREE_DEFAULT_INTERNAL_COMPANY': {
+ 'name': _('Default internal company'),
+ 'description': _('Internal company which represents this organization'),
+ 'default': '',
+ 'model': 'company.company',
+ 'model_filters': {'is_internal': True},
+ 'validator': validate_internal_company,
+ },
'INVENTREE_BASE_URL': {
'name': _('Base URL'),
'description': _('Base URL for server instance'),
diff --git a/src/backend/InvenTree/common/tests.py b/src/backend/InvenTree/common/tests.py
index 96ee1e31ab..f215321666 100644
--- a/src/backend/InvenTree/common/tests.py
+++ b/src/backend/InvenTree/common/tests.py
@@ -756,6 +756,30 @@ class GlobalSettingsApiTest(InvenTreeAPITestCase):
# There should be no user sessions now
self.assertEqual(self.user.usersession_set.count(), 0)
+ def test_model_filters(self):
+ """Test that model-backed settings expose their model filters."""
+ for key, model_name, filters in [
+ (
+ 'INVENTREE_DEFAULT_INTERNAL_COMPANY',
+ 'company.company',
+ {'is_internal': True},
+ ),
+ (
+ 'PURCHASEORDER_DEFAULT_RECEIVE_LOCATION',
+ 'stock.stocklocation',
+ {'structural': False},
+ ),
+ ]:
+ url = reverse('api-global-setting-detail', kwargs={'key': key})
+ response = self.get(url, expected_code=200)
+
+ self.assertEqual(response.data['model_name'], model_name)
+ self.assertEqual(response.data['model_filters'], filters)
+
+ # Settings without a model have no filters
+ url = reverse('api-global-setting-detail', kwargs={'key': 'INVENTREE_INSTANCE'})
+ self.assertIsNone(self.get(url, expected_code=200).data['model_filters'])
+
def test_api_detail(self):
"""Test that we can access the detail view for a setting based on the ."""
# These keys are invalid, and should return 404
diff --git a/src/backend/InvenTree/company/api.py b/src/backend/InvenTree/company/api.py
index b48e581975..c942aabb9d 100644
--- a/src/backend/InvenTree/company/api.py
+++ b/src/backend/InvenTree/company/api.py
@@ -45,7 +45,14 @@ class CompanyFilter(FilterSet):
"""Metaclass options."""
model = Company
- fields = ['is_customer', 'is_manufacturer', 'is_supplier', 'name', 'active']
+ fields = [
+ 'is_customer',
+ 'is_manufacturer',
+ 'is_supplier',
+ 'is_internal',
+ 'name',
+ 'active',
+ ]
tag_name = common.filters.TagsFilter()
diff --git a/src/backend/InvenTree/company/migrations/0083_company_is_internal.py b/src/backend/InvenTree/company/migrations/0083_company_is_internal.py
new file mode 100644
index 0000000000..d85f362726
--- /dev/null
+++ b/src/backend/InvenTree/company/migrations/0083_company_is_internal.py
@@ -0,0 +1,22 @@
+# Generated by Django 5.2.17 on 2026-10-14 02:54
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ("company", "0082_address_phone_email"),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name="company",
+ name="is_internal",
+ field=models.BooleanField(
+ default=False,
+ help_text="Does this company represent your own organization?",
+ verbose_name="Is internal",
+ ),
+ ),
+ ]
diff --git a/src/backend/InvenTree/company/models.py b/src/backend/InvenTree/company/models.py
index c3b7f5f133..ecea00dc7a 100644
--- a/src/backend/InvenTree/company/models.py
+++ b/src/backend/InvenTree/company/models.py
@@ -27,6 +27,7 @@ import InvenTree.ready
import InvenTree.validators
import report.mixins
from common.currency import currency_code_default
+from common.settings import get_global_setting
from InvenTree.fields import InvenTreeURLField, RoundingDecimalField
from order.status_codes import PurchaseOrderStatusGroups
@@ -91,6 +92,7 @@ class Company(
- A supplier is a company from which parts can be purchased
- A customer is a company to which parts can be sold
- A manufacturer is a company which manufactures a raw good (they may or may not be a "supplier" also)
+ - An internal company represents your own organization (or one of its entities / sites)
Attributes:
@@ -107,6 +109,7 @@ class Company(
is_customer: boolean value, is this company a customer
is_supplier: boolean value, is this company a supplier
is_manufacturer: boolean value, is this company a manufacturer
+ is_internal: boolean value, does this company represent your own organization
currency_code: Specifies the default currency for the company
tax_id: Tax ID for the company
"""
@@ -129,6 +132,29 @@ class Company(
"""Return the API URL associated with the Company model."""
return reverse('api-company-list')
+ @classmethod
+ def get_default_internal(cls) -> Optional['Company']:
+ """Return the default internal company for this InvenTree instance.
+
+ - If the INVENTREE_DEFAULT_INTERNAL_COMPANY setting points to an internal company, return it
+ - Otherwise, if exactly one internal company exists, return it
+ - Otherwise, return None
+ """
+ internal = cls.objects.filter(is_internal=True)
+
+ if pk := get_global_setting(
+ 'INVENTREE_DEFAULT_INTERNAL_COMPANY', backup_value=None
+ ):
+ try:
+ if company := internal.filter(pk=int(pk)).first():
+ return company
+ except (TypeError, ValueError):
+ pass
+
+ companies = list(internal[:2])
+
+ return companies[0] if len(companies) == 1 else None
+
def report_context(self) -> CompanyReportContext:
"""Generate a dict of context data to provide to the reporting framework."""
return {
@@ -212,6 +238,12 @@ class Company(
help_text=_('Does this company manufacture parts?'),
)
+ is_internal = models.BooleanField(
+ default=False,
+ verbose_name=_('Is internal'),
+ help_text=_('Does this company represent your own organization?'),
+ )
+
currency = models.CharField(
max_length=3,
verbose_name=_('Currency'),
diff --git a/src/backend/InvenTree/company/serializers.py b/src/backend/InvenTree/company/serializers.py
index 586956b6a5..35d7b99acd 100644
--- a/src/backend/InvenTree/company/serializers.py
+++ b/src/backend/InvenTree/company/serializers.py
@@ -146,6 +146,7 @@ class CompanySerializer(
'is_customer',
'is_manufacturer',
'is_supplier',
+ 'is_internal',
'parts_supplied',
'parts_manufactured',
'primary_address',
diff --git a/src/backend/InvenTree/company/test_api.py b/src/backend/InvenTree/company/test_api.py
index a8139b8b02..04f8f7fb2c 100644
--- a/src/backend/InvenTree/company/test_api.py
+++ b/src/backend/InvenTree/company/test_api.py
@@ -71,6 +71,35 @@ class CompanyTest(InvenTreeAPITestCase):
response = self.get(url, data)
self.assertEqual(len(response.data), 2)
+ def test_company_internal(self):
+ """Test the 'is_internal' field and filter."""
+ url = reverse('api-company-list')
+
+ self.assertEqual(len(self.get(url, {'is_internal': True}).data), 0)
+
+ response = self.post(
+ url,
+ {'name': 'Our Company', 'is_internal': True, 'is_supplier': False},
+ expected_code=201,
+ )
+ self.assertTrue(response.data['is_internal'])
+ pk = response.data['pk']
+
+ response = self.get(url, {'is_internal': True})
+ self.assertEqual(len(response.data), 1)
+ self.assertEqual(response.data[0]['pk'], pk)
+
+ self.assertEqual(len(self.get(url, {'is_internal': False}).data), 3)
+
+ # Only an internal company can be selected as the default
+ setting_url = reverse(
+ 'api-global-setting-detail',
+ kwargs={'key': 'INVENTREE_DEFAULT_INTERNAL_COMPANY'},
+ )
+
+ self.patch(setting_url, {'value': self.acme.pk}, expected_code=400)
+ self.patch(setting_url, {'value': pk}, expected_code=200)
+
def test_company_detail(self):
"""Tests for the Company detail endpoint."""
url = reverse('api-company-detail', kwargs={'pk': self.acme.pk})
diff --git a/src/backend/InvenTree/company/tests.py b/src/backend/InvenTree/company/tests.py
index 3187b0ee36..8bc8af01d5 100644
--- a/src/backend/InvenTree/company/tests.py
+++ b/src/backend/InvenTree/company/tests.py
@@ -5,6 +5,8 @@ import os
from django.core.exceptions import ValidationError
from django.test import TestCase
+from common.models import InvenTreeSetting
+from common.settings import set_global_setting
from part.models import Part
from .models import (
@@ -159,6 +161,57 @@ class ContactSimpleTest(TestCase):
self.assertEqual(Contact.objects.count(), 0)
+class InternalCompanyTest(TestCase):
+ """Unit tests for internal company support."""
+
+ SETTING = 'INVENTREE_DEFAULT_INTERNAL_COMPANY'
+
+ @classmethod
+ def setUpTestData(cls):
+ """Create some companies to work with."""
+ super().setUpTestData()
+
+ cls.supplier = Company.objects.create(name='Supplier', is_supplier=True)
+ cls.hq = Company.objects.create(name='HQ', is_supplier=False, is_internal=True)
+
+ def test_default(self):
+ """Test the Company.get_default_internal() helper."""
+ set_global_setting(self.SETTING, '')
+
+ # A single internal company is used as the default
+ self.assertEqual(Company.get_default_internal(), self.hq)
+
+ # Multiple internal companies, with no setting, is ambiguous
+ site = Company.objects.create(name='Site', is_supplier=False, is_internal=True)
+ self.assertIsNone(Company.get_default_internal())
+
+ # The setting selects between them
+ set_global_setting(self.SETTING, site.pk)
+ self.assertEqual(Company.get_default_internal(), site)
+
+ # A setting which no longer points to an internal company is ignored
+ site.is_internal = False
+ site.save()
+ self.assertEqual(Company.get_default_internal(), self.hq)
+
+ # No internal companies at all
+ Company.objects.filter(is_internal=True).update(is_internal=False)
+ self.assertIsNone(Company.get_default_internal())
+
+ def test_setting_validation(self):
+ """The setting may only reference an internal company."""
+ setting = InvenTreeSetting.get_setting_object(self.SETTING, create=True)
+
+ for value in [self.supplier.pk, 99999, 'abc']:
+ setting.value = value
+ with self.assertRaises(ValidationError):
+ setting.full_clean()
+
+ for value in ['', self.hq.pk]:
+ setting.value = value
+ setting.full_clean()
+
+
class AddressTest(TestCase):
"""Unit tests for the Address model."""
diff --git a/src/backend/InvenTree/importer/tests.py b/src/backend/InvenTree/importer/tests.py
index 04757fbeac..706c44b203 100644
--- a/src/backend/InvenTree/importer/tests.py
+++ b/src/backend/InvenTree/importer/tests.py
@@ -45,7 +45,7 @@ class ImporterTest(ImporterMixin, InvenTreeTestCase):
session.extract_columns()
- self.assertEqual(session.column_mappings.count(), 13)
+ self.assertEqual(session.column_mappings.count(), 14)
# Check some of the field mappings
for field, col in [
diff --git a/src/backend/InvenTree/report/models.py b/src/backend/InvenTree/report/models.py
index b8ec7dadf2..b8cde506e3 100644
--- a/src/backend/InvenTree/report/models.py
+++ b/src/backend/InvenTree/report/models.py
@@ -30,6 +30,7 @@ import report.helpers
import report.validators
from common.models import DataOutput, RenderChoices, UpdatedUserMixin
from common.settings import get_global_setting
+from company.models import Company
from InvenTree.helpers_model import get_base_url
from InvenTree.models import MetadataMixin
from plugin import InvenTreePlugin, PluginMixinEnum
@@ -158,6 +159,7 @@ class BaseContextExtension(TypedDict):
template_name: Name of the report template
template_revision: Revision of the report template
user: User who is creating the report (if available)
+ internal_company: The default internal company (if defined) which represents this organization
report_vars: Private dict for the {% get_var %} / {% set_var %} template tags
"""
@@ -169,6 +171,7 @@ class BaseContextExtension(TypedDict):
template_name: str
template_revision: int
user: Optional[AbstractUser]
+ internal_company: Optional[Company]
report_vars: dict
@@ -410,6 +413,13 @@ class ReportTemplateBase(
"""Return a filter dict which can be applied to the target model."""
return report.validators.validate_filters(self.filters, model=self.get_model())
+ def get_internal_company(self) -> Optional[Company]:
+ """Return the default internal company, cached for the lifetime of this template instance."""
+ if not hasattr(self, '_internal_company'):
+ self._internal_company = Company.get_default_internal()
+
+ return self._internal_company
+
def base_context(self, **kwargs) -> BaseContextExtension:
"""Return base context data (available to all templates)."""
return {
@@ -421,6 +431,7 @@ class ReportTemplateBase(
'template_name': self.name,
'template_revision': self.revision,
'user': kwargs.get('user'),
+ 'internal_company': self.get_internal_company(),
# A private, per-render dict for the {% get_var %} / {% set_var %} tags.
# This is discarded once rendering of *this* instance completes,
# and is never shared between instances, reports, or requests.
diff --git a/src/backend/InvenTree/report/tests.py b/src/backend/InvenTree/report/tests.py
index 9a7f9c7619..d7286cbd03 100644
--- a/src/backend/InvenTree/report/tests.py
+++ b/src/backend/InvenTree/report/tests.py
@@ -67,6 +67,23 @@ class ReportTest(InvenTreeAPITestCase):
return super().setUp()
+ def test_internal_company_context(self):
+ """Test that the default internal company is available in the base context."""
+ from company.models import Company
+
+ template = ReportTemplate.objects.first()
+ self.assertIsNone(template.base_context()['internal_company'])
+
+ company = Company.objects.create(
+ name='Our Company', is_supplier=False, is_internal=True
+ )
+
+ # Value is cached against the template instance
+ self.assertIsNone(template.base_context()['internal_company'])
+
+ template = ReportTemplate.objects.get(pk=template.pk)
+ self.assertEqual(template.base_context()['internal_company'], company)
+
def test_list_endpoint(self):
"""Test that the LIST endpoint works for each report."""
url = reverse('api-report-template-list')
diff --git a/src/frontend/src/forms/CompanyForms.tsx b/src/frontend/src/forms/CompanyForms.tsx
index 4323a6b200..48db3c7368 100644
--- a/src/frontend/src/forms/CompanyForms.tsx
+++ b/src/frontend/src/forms/CompanyForms.tsx
@@ -189,6 +189,7 @@ export function companyFields({
is_supplier: {},
is_manufacturer: {},
is_customer: {},
+ is_internal: {},
active: {},
duplicate: DuplicateField({
originalId: duplicateCompanyId,
diff --git a/src/frontend/src/functions/icons.tsx b/src/frontend/src/functions/icons.tsx
index 13e9f9ed79..e34723e9a3 100644
--- a/src/frontend/src/functions/icons.tsx
+++ b/src/frontend/src/functions/icons.tsx
@@ -10,6 +10,7 @@ import {
IconBrandTelegram,
IconBuilding,
IconBuildingFactory2,
+ IconBuildingSkyscraper,
IconBuildingStore,
IconBusinessplan,
IconCalendar,
@@ -158,6 +159,7 @@ const icons: InvenTreeIconType = {
manufacturers: IconBuildingFactory2,
suppliers: IconBuilding,
customers: IconBuildingStore,
+ internal_company: IconBuildingSkyscraper,
purchase_orders: IconShoppingCart,
return_orders: IconTruckReturn,
transfer_orders: IconTransfer,
diff --git a/src/frontend/src/pages/Index/Settings/AdminCenter/Index.tsx b/src/frontend/src/pages/Index/Settings/AdminCenter/Index.tsx
index df3c90b5d2..232150d2bd 100644
--- a/src/frontend/src/pages/Index/Settings/AdminCenter/Index.tsx
+++ b/src/frontend/src/pages/Index/Settings/AdminCenter/Index.tsx
@@ -4,6 +4,7 @@ import type { PanelGroupType, PanelType } from '@lib/types/Panel';
import { t } from '@lingui/core/macro';
import { Stack } from '@mantine/core';
import {
+ IconBuilding,
IconCoins,
IconCpu,
IconDevicesPc,
@@ -35,6 +36,7 @@ import { PanelGroup } from '../../../../components/panels/PanelGroup';
import { GlobalSettingList } from '../../../../components/settings/SettingList';
import { Loadable } from '../../../../functions/loading';
import { useUserState } from '../../../../states/UserState';
+import { CompanyTable } from '../../../../tables/company/CompanyTable';
import ParameterTemplateTable from '../../../../tables/general/ParameterTemplateTable';
import SelectionListTable from '../../../../tables/settings/SelectionListTable';
@@ -176,6 +178,17 @@ export default function AdminCenter() {
icon: ,
content:
},
+ {
+ name: 'companies',
+ label: t`Companies`,
+ icon: ,
+ content: (
+
+
+
+
+ )
+ },
{
name: 'currencies',
label: t`Currencies`,
@@ -299,6 +312,7 @@ export default function AdminCenter() {
'barcode-history',
'background',
'errors',
+ 'companies',
'currencies',
'email'
]
diff --git a/src/frontend/src/pages/Index/Settings/SystemSettings.tsx b/src/frontend/src/pages/Index/Settings/SystemSettings.tsx
index fec3611353..e9b6227e1f 100644
--- a/src/frontend/src/pages/Index/Settings/SystemSettings.tsx
+++ b/src/frontend/src/pages/Index/Settings/SystemSettings.tsx
@@ -47,6 +47,7 @@ export default function SystemSettings() {
keys={[
'INVENTREE_BASE_URL',
'INVENTREE_COMPANY_NAME',
+ 'INVENTREE_DEFAULT_INTERNAL_COMPANY',
'INVENTREE_INSTANCE',
'INVENTREE_INSTANCE_TITLE',
'INVENTREE_INSTANCE_ID',
diff --git a/src/frontend/src/pages/company/CompanyDetailsPanel.tsx b/src/frontend/src/pages/company/CompanyDetailsPanel.tsx
index b98d67515c..1de2ef55cb 100644
--- a/src/frontend/src/pages/company/CompanyDetailsPanel.tsx
+++ b/src/frontend/src/pages/company/CompanyDetailsPanel.tsx
@@ -83,6 +83,13 @@ export function CompanyDetailsPanel({
name: 'is_customer',
label: t`Customer`,
icon: 'customers'
+ },
+ {
+ type: 'boolean',
+ name: 'is_internal',
+ label: t`Internal`,
+ icon: 'internal_company',
+ hidden: !instance?.is_internal
}
];
diff --git a/src/frontend/src/tables/company/CompanyTable.tsx b/src/frontend/src/tables/company/CompanyTable.tsx
index f4705f363b..0ede197eee 100644
--- a/src/frontend/src/tables/company/CompanyTable.tsx
+++ b/src/frontend/src/tables/company/CompanyTable.tsx
@@ -27,6 +27,13 @@ import { usePreviewDrawerState } from '../../states/PreviewDrawerState';
import { useUserSettingsState } from '../../states/SettingsStates';
import { useUserState } from '../../states/UserState';
+type CompanyTableType =
+ | 'all'
+ | 'internal'
+ | 'supplier'
+ | 'manufacturer'
+ | 'customer';
+
/**
* A table which displays a list of company records,
* based on the provided filter parameters
@@ -34,10 +41,12 @@ import { useUserState } from '../../states/UserState';
export function CompanyTable({
companyType,
params,
+ initialData,
path
}: Readonly<{
- companyType?: string;
+ companyType?: CompanyTableType;
params?: any;
+ initialData?: any;
path?: string;
}>) {
const table = useTable(`company-${companyType ?? 'index'}`, {
@@ -77,18 +86,54 @@ export function CompanyTable({
sortable: true,
switchable: true
}),
+ BooleanColumn({
+ accessor: 'is_supplier',
+ filter: 'is_supplier',
+ title: t`Supplier`,
+ sortable: true,
+ switchable: true,
+ hidden: companyType === 'supplier',
+ defaultVisible: false
+ }),
+ BooleanColumn({
+ accessor: 'is_manufacturer',
+ filter: 'is_manufacturer',
+ title: t`Manufacturer`,
+ sortable: true,
+ switchable: true,
+ hidden: companyType === 'manufacturer',
+ defaultVisible: false
+ }),
+ BooleanColumn({
+ accessor: 'is_customer',
+ filter: 'is_customer',
+ title: t`Customer`,
+ sortable: true,
+ switchable: true,
+ hidden: companyType === 'customer',
+ defaultVisible: false
+ }),
+ BooleanColumn({
+ accessor: 'is_internal',
+ filter: 'is_internal',
+ title: t`Internal`,
+ sortable: true,
+ switchable: true,
+ hidden: companyType === 'internal',
+ defaultVisible: false
+ }),
{
accessor: 'website',
sortable: false
}
];
- }, []);
+ }, [companyType]);
const newCompany = useCreateApiFormModal({
url: ApiEndpoints.company_list,
title: t`Add Company`,
fields: companyFields(),
- initialData: params,
+ initialData: initialData ?? params,
follow: true,
modelType: ModelType.company,
keepOpenOption: true
@@ -126,6 +171,11 @@ export function CompanyTable({
label: t`Customer`,
description: t`Show companies which are customers`
},
+ {
+ name: 'is_internal',
+ label: t`Internal`,
+ description: t`Show companies which represent your own organization`
+ },
TagsFilter({ modelType: ModelType.company })
];
}, []);