Skip to content

Commit cfb23ad

Browse files
arthansonbctiemann
authored andcommitted
16783 Add status field to InventoryItem (#17627)
* 16783 Add status field to InventoryItem * 16783 fix tests * 16783 fix tests * 16783 review changes
1 parent a320bda commit cfb23ad

File tree

14 files changed

+107
-19
lines changed

14 files changed

+107
-19
lines changed

docs/models/dcim/inventoryitem.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,7 @@ The serial number assigned by the manufacturer.
4444
### Asset Tag
4545

4646
A unique, locally-administered label used to identify hardware resources.
47+
48+
### Status
49+
50+
The inventory item's operational status.

netbox/dcim/api/serializers_/device_components.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -345,11 +345,12 @@ class InventoryItemSerializer(NetBoxModelSerializer):
345345
)
346346
component = serializers.SerializerMethodField(read_only=True, allow_null=True)
347347
_depth = serializers.IntegerField(source='level', read_only=True)
348+
status = ChoiceField(choices=InventoryItemStatusChoices, required=False)
348349

349350
class Meta:
350351
model = InventoryItem
351352
fields = [
352-
'id', 'url', 'display_url', 'display', 'device', 'parent', 'name', 'label', 'role', 'manufacturer',
353+
'id', 'url', 'display_url', 'display', 'device', 'parent', 'name', 'label', 'status', 'role', 'manufacturer',
353354
'part_id', 'serial', 'asset_tag', 'discovered', 'description', 'component_type', 'component_id',
354355
'component', 'tags', 'custom_fields', 'created', 'last_updated', '_depth',
355356
]

netbox/dcim/choices.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1656,3 +1656,27 @@ class VirtualDeviceContextStatusChoices(ChoiceSet):
16561656
(STATUS_PLANNED, _('Planned'), 'cyan'),
16571657
(STATUS_OFFLINE, _('Offline'), 'red'),
16581658
]
1659+
1660+
1661+
#
1662+
# InventoryItem
1663+
#
1664+
1665+
class InventoryItemStatusChoices(ChoiceSet):
1666+
key = 'InventoryItem.status'
1667+
1668+
STATUS_OFFLINE = 'offline'
1669+
STATUS_ACTIVE = 'active'
1670+
STATUS_PLANNED = 'planned'
1671+
STATUS_STAGED = 'staged'
1672+
STATUS_FAILED = 'failed'
1673+
STATUS_DECOMMISSIONING = 'decommissioning'
1674+
1675+
CHOICES = [
1676+
(STATUS_OFFLINE, _('Offline'), 'gray'),
1677+
(STATUS_ACTIVE, _('Active'), 'green'),
1678+
(STATUS_PLANNED, _('Planned'), 'cyan'),
1679+
(STATUS_STAGED, _('Staged'), 'blue'),
1680+
(STATUS_FAILED, _('Failed'), 'red'),
1681+
(STATUS_DECOMMISSIONING, _('Decommissioning'), 'yellow'),
1682+
]

netbox/dcim/filtersets.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1860,10 +1860,14 @@ class InventoryItemFilterSet(DeviceComponentFilterSet, NetBoxModelFilterSet):
18601860
serial = MultiValueCharFilter(
18611861
lookup_expr='iexact'
18621862
)
1863+
status = django_filters.MultipleChoiceFilter(
1864+
choices=InventoryItemStatusChoices,
1865+
null_value=None
1866+
)
18631867

18641868
class Meta:
18651869
model = InventoryItem
1866-
fields = ('id', 'name', 'label', 'part_id', 'asset_tag', 'description', 'discovered')
1870+
fields = ('id', 'name', 'label', 'part_id', 'asset_tag', 'status', 'description', 'discovered')
18671871

18681872
def search(self, queryset, name, value):
18691873
if not value.strip():

netbox/dcim/forms/bulk_edit.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1661,10 +1661,16 @@ class InventoryItemBulkEditForm(
16611661
queryset=Manufacturer.objects.all(),
16621662
required=False
16631663
)
1664+
status = forms.ChoiceField(
1665+
label=_('Status'),
1666+
choices=add_blank_choice(InventoryItemStatusChoices),
1667+
required=False,
1668+
initial=''
1669+
)
16641670

16651671
model = InventoryItem
16661672
fieldsets = (
1667-
FieldSet('device', 'label', 'role', 'manufacturer', 'part_id', 'description'),
1673+
FieldSet('device', 'label', 'role', 'manufacturer', 'part_id', 'status', 'description'),
16681674
)
16691675
nullable_fields = ('label', 'role', 'manufacturer', 'part_id', 'description')
16701676

netbox/dcim/forms/bulk_import.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1103,11 +1103,16 @@ class InventoryItemImportForm(NetBoxModelImportForm):
11031103
required=False,
11041104
help_text=_('Component Name')
11051105
)
1106+
status = CSVChoiceField(
1107+
label=_('Status'),
1108+
choices=InventoryItemStatusChoices,
1109+
help_text=_('Operational status')
1110+
)
11061111

11071112
class Meta:
11081113
model = InventoryItem
11091114
fields = (
1110-
'device', 'name', 'label', 'role', 'manufacturer', 'parent', 'part_id', 'serial', 'asset_tag', 'discovered',
1115+
'device', 'name', 'label', 'status', 'role', 'manufacturer', 'parent', 'part_id', 'serial', 'asset_tag', 'discovered',
11111116
'description', 'tags', 'component_type', 'component_name',
11121117
)
11131118

netbox/dcim/forms/filtersets.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@
3535
'LocationFilterForm',
3636
'ManufacturerFilterForm',
3737
'ModuleFilterForm',
38-
'ModuleFilterForm',
3938
'ModuleBayFilterForm',
4039
'ModuleTypeFilterForm',
4140
'PlatformFilterForm',
@@ -1553,6 +1552,11 @@ class InventoryItemFilterForm(DeviceComponentFilterForm):
15531552
choices=BOOLEAN_WITH_BLANK_CHOICES
15541553
)
15551554
)
1555+
status = forms.MultipleChoiceField(
1556+
label=_('Status'),
1557+
choices=InventoryItemStatusChoices,
1558+
required=False
1559+
)
15561560
tag = TagFilterField(model)
15571561

15581562

netbox/dcim/forms/model_forms.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1576,7 +1576,7 @@ class InventoryItemForm(DeviceComponentForm):
15761576
)
15771577

15781578
fieldsets = (
1579-
FieldSet('device', 'parent', 'name', 'label', 'role', 'description', 'tags', name=_('Inventory Item')),
1579+
FieldSet('device', 'parent', 'name', 'label', 'status', 'role', 'description', 'tags', name=_('Inventory Item')),
15801580
FieldSet('manufacturer', 'part_id', 'serial', 'asset_tag', name=_('Hardware')),
15811581
FieldSet(
15821582
TabbedGroups(
@@ -1596,7 +1596,7 @@ class Meta:
15961596
model = InventoryItem
15971597
fields = [
15981598
'device', 'parent', 'name', 'label', 'role', 'manufacturer', 'part_id', 'serial', 'asset_tag',
1599-
'description', 'tags',
1599+
'status', 'description', 'tags',
16001600
]
16011601

16021602
def __init__(self, *args, **kwargs):
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Generated by Django 5.0.9 on 2024-09-26 20:19
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
('dcim', '0190_nested_modules'),
10+
]
11+
12+
operations = [
13+
migrations.AddField(
14+
model_name='inventoryitem',
15+
name='status',
16+
field=models.CharField(default='active', max_length=50),
17+
),
18+
]

netbox/dcim/models/device_components.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1243,6 +1243,12 @@ class InventoryItem(MPTTModel, ComponentModel, TrackingModelMixin):
12431243
ct_field='component_type',
12441244
fk_field='component_id'
12451245
)
1246+
status = models.CharField(
1247+
verbose_name=_('status'),
1248+
max_length=50,
1249+
choices=InventoryItemStatusChoices,
1250+
default=InventoryItemStatusChoices.STATUS_ACTIVE
1251+
)
12461252
role = models.ForeignKey(
12471253
to='dcim.InventoryItemRole',
12481254
on_delete=models.PROTECT,
@@ -1284,7 +1290,7 @@ class InventoryItem(MPTTModel, ComponentModel, TrackingModelMixin):
12841290

12851291
objects = TreeManager()
12861292

1287-
clone_fields = ('device', 'parent', 'role', 'manufacturer', 'part_id',)
1293+
clone_fields = ('device', 'parent', 'role', 'manufacturer', 'status', 'part_id')
12881294

12891295
class Meta:
12901296
ordering = ('device__id', 'parent__id', '_name')
@@ -1333,3 +1339,6 @@ def clean(self):
13331339
raise ValidationError({
13341340
"device": _("Cannot assign inventory item to component on another device")
13351341
})
1342+
1343+
def get_status_color(self):
1344+
return InventoryItemStatusChoices.colors.get(self.status)

0 commit comments

Comments
 (0)