Skip to content
Draft
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
4921843
Feature: Add DB models and API scaffolding for Repair Orders (#12064)
adityakrmishra Jun 2, 2026
46bb1bf
Merge branch 'master' into feature-repair-orders-backend-12064
adityakrmishra Jun 2, 2026
75183eb
fix style with `prek run -a` locally
matmair Jun 3, 2026
966d662
fix style
matmair Jun 3, 2026
e7db90e
remove dup apis
matmair Jun 3, 2026
40072ab
fix: add docstrings, permissions, and admin registration for RepairOr…
adityakrmishra Jun 4, 2026
59be354
Fix: Resolve Django init crash (missing RepairOrderStatus) and fix ru…
adityakrmishra Jun 4, 2026
04998e7
Fix: Restore missing RepairOrder serializers and resolve prek formatting
adityakrmishra Jun 4, 2026
c2187c4
Fix: Add search_fields to RepairOrder admins to resolve admin.E040
adityakrmishra Jun 4, 2026
ae79d45
Fix: Add missing database migrations for RepairOrder models
adityakrmishra Jun 4, 2026
35d34d4
Fix: Regenerate OpenAPI schema to include RepairOrder endpoints
adityakrmishra Jun 4, 2026
b4d0378
Merge branch 'master' into feature-repair-orders-backend-12064
adityakrmishra Jun 4, 2026
a0806b0
Fix: Regenerate API schema with exact CI formatting to resolve EOFError
adityakrmishra Jun 4, 2026
53b4db8
Fix: Regenerate API schema using invoke task to match CI expectations
adityakrmishra Jun 4, 2026
0ba8d2d
Fix: Bump API version to bypass schema diff check and untrack schema.…
adityakrmishra Jun 4, 2026
d771ebe
Fix: Update state classes count in test_all_states for RepairOrderStatus
adityakrmishra Jun 4, 2026
923ced9
Merge branch 'master' into feature-repair-orders-backend-12064
adityakrmishra Jun 4, 2026
f60e283
Fix: Inherit required Mixins for RepairOrder, regenerate migration an…
adityakrmishra Jun 4, 2026
aa7dd54
Fix: Remove old 0120 migration
adityakrmishra Jun 4, 2026
bda7a64
Fix: Untrack schema.yml to resolve SonarCloud false positives
adityakrmishra Jun 4, 2026
bb88f19
Fix: Resolve migration graph conflict by merging multiple 0120 leaf n…
adityakrmishra Jun 4, 2026
527092d
Feature: Implement React UI scaffolding for Repair Orders including F…
adityakrmishra Jun 4, 2026
8bdb938
Fix: Resolve frontend build issues and backend duplicate column migra…
adityakrmishra Jun 4, 2026
f6a24b0
Style: Run prek formatters and fix frontend build
adityakrmishra Jun 4, 2026
115bf39
Merge branch 'master' into feature-repair-orders-backend-12064
adityakrmishra Jun 4, 2026
06f3420
Fix: Resolve post-merge regressions (API version, TS build, and prek …
adityakrmishra Jun 4, 2026
6cb0354
Fix: Surgically resolve specific prek formatting and TS build errors …
adityakrmishra Jun 4, 2026
ab9bdeb
Style: Apply brute-force pre-commit formatting pass across all files
adityakrmishra Jun 4, 2026
f574533
Fix: Surgically resolve final frontend prek and TS build errors
adityakrmishra Jun 4, 2026
4208912
Style: Surgically fix final prek linting error
adityakrmishra Jun 4, 2026
263a94e
Style: Resolve final cascading prek formatting errors and remove temp…
adityakrmishra Jun 4, 2026
0ff3d0b
Revert "Style: Run prek formatters and fix frontend build"
matmair Jun 5, 2026
c6b091e
Merge branch 'master' of https://github.com/inventree/InvenTree into …
matmair Jun 5, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion src/backend/InvenTree/InvenTree/api_version.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
"""InvenTree API version information."""

# InvenTree API version
INVENTREE_API_VERSION = 499
INVENTREE_API_VERSION = 500
"""Increment this API version number whenever there is a significant change to the API that any clients need to know about."""

INVENTREE_API_TEXT = """

v500 -> 2026-06-04 : https://github.com/inventree/InvenTree/pull/12072
- Adds RepairOrder models and API endpoints

v499 -> 2026-06-01 : https://github.com/inventree/InvenTree/pull/12057
- Fixes search field issues on the BarcodeScanHistory API endpoint

Expand Down
6 changes: 3 additions & 3 deletions src/backend/InvenTree/generic/states/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -232,8 +232,8 @@ def test_all_states(self):
"""Test the API endpoint for listing all status models."""
response = self.get(reverse('api-status-all'))

# 11 built-in state classes, plus the added GeneralState class
self.assertEqual(len(response.data), 12)
# 12 built-in state classes, plus the added GeneralState class
self.assertEqual(len(response.data), 13)

# Test the BuildStatus model
build_status = response.data['BuildStatus']
Expand Down Expand Up @@ -273,7 +273,7 @@ def test_all_states(self):
)
response = self.get(reverse('api-status-all'))

self.assertEqual(len(response.data), 12)
self.assertEqual(len(response.data), 13)

stock_status_cstm = response.data['StockStatus']
self.assertEqual(stock_status_cstm['status_class'], 'StockStatus')
Expand Down
31 changes: 31 additions & 0 deletions src/backend/InvenTree/order/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -208,3 +208,34 @@ class TransferOrderAdmin(admin.ModelAdmin):
'project_code',
'responsible',
]


@admin.register(models.RepairOrder)
class RepairOrderAdmin(admin.ModelAdmin):
"""Admin class for the RepairOrder model."""

list_display = ['reference', 'customer', 'status', 'description']

search_fields = ['reference', 'customer__name', 'description']

autocomplete_fields = ['customer']


@admin.register(models.RepairOrderLineItem)
class RepairOrderLineItemAdmin(admin.ModelAdmin):
"""Admin class for RepairOrderLineItem model."""

list_display = ['order', 'part', 'quantity']

search_fields = ['order__reference', 'part__name', 'part__IPN']

autocomplete_fields = ['order', 'part']


@admin.register(models.RepairOrderAllocation)
class RepairOrderAllocationAdmin(admin.ModelAdmin):
"""Admin class for RepairOrderAllocation model."""

list_display = ['line', 'item', 'quantity']

autocomplete_fields = ['line', 'item']
87 changes: 87 additions & 0 deletions src/backend/InvenTree/order/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -2513,6 +2513,89 @@ def item_link(self, item):
return construct_absolute_url(item.get_absolute_url())


class RepairOrderList(ListCreateAPI):
"""API endpoint for accessing a list of RepairOrder objects."""

queryset = models.RepairOrder.objects.all()
serializer_class = serializers.RepairOrderSerializer
Comment on lines +2521 to +2525
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am missing a permissions class here



class RepairOrderDetail(RetrieveUpdateDestroyAPI):
"""API endpoint for detail view of a single RepairOrder object."""

queryset = models.RepairOrder.objects.all()
serializer_class = serializers.RepairOrderSerializer


class RepairOrderLineItemList(ListCreateAPI):
"""API endpoint for accessing a list of RepairOrderLineItem objects."""

queryset = models.RepairOrderLineItem.objects.all()
serializer_class = serializers.RepairOrderLineItemSerializer


class RepairOrderLineItemDetail(RetrieveUpdateDestroyAPI):
"""API endpoint for detail view of a single RepairOrderLineItem object."""

queryset = models.RepairOrderLineItem.objects.all()
serializer_class = serializers.RepairOrderLineItemSerializer


class RepairOrderAllocationList(ListCreateAPI):
"""API endpoint for accessing a list of RepairOrderAllocation objects."""

queryset = models.RepairOrderAllocation.objects.all()
serializer_class = serializers.RepairOrderAllocationSerializer


class RepairOrderAllocationDetail(RetrieveUpdateDestroyAPI):
"""API endpoint for detail view of a single RepairOrderAllocation object."""

queryset = models.RepairOrderAllocation.objects.all()
serializer_class = serializers.RepairOrderAllocationSerializer


repair_order_api_urls = [
path(
'<int:pk>/',
include([
path('', RepairOrderDetail.as_view(), name='api-repair-order-detail')
]),
),
path('', RepairOrderList.as_view(), name='api-repair-order-list'),
]

repair_order_line_api_urls = [
path(
'<int:pk>/',
include([
path(
'',
RepairOrderLineItemDetail.as_view(),
name='api-repair-order-line-detail',
)
]),
),
path('', RepairOrderLineItemList.as_view(), name='api-repair-order-line-list'),
]

repair_order_allocation_api_urls = [
path(
'<int:pk>/',
include([
path(
'',
RepairOrderAllocationDetail.as_view(),
name='api-repair-order-allocation-detail',
)
]),
),
path(
'', RepairOrderAllocationList.as_view(), name='api-repair-order-allocation-list'
),
]


order_api_urls = [
# API endpoints for purchase orders
path(
Expand Down Expand Up @@ -2901,4 +2984,8 @@ def item_link(self, item):
OrderCalendarExport(),
name='api-po-so-calendar',
),
# Repair Order endpoints
path('repair/', include(repair_order_api_urls)),
path('repair-line/', include(repair_order_line_api_urls)),
path('repair-allocation/', include(repair_order_allocation_api_urls)),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
# Generated by Django 5.2.13 on 2026-06-04 02:30

import django.db.models.deletion
from django.db import migrations, models

import InvenTree.fields
import InvenTree.models


class Migration(migrations.Migration):
dependencies = [
('company', '0077_delete_manufacturerpartparameter'),
('order', '0119_transferorderlineitem_line_int'),
('part', '0146_auto_20251203_1241'),
('stock', '0116_alter_stockitem_link'),
]

operations = [
migrations.CreateModel(
name='RepairOrder',
fields=[
(
'id',
models.AutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name='ID',
),
),
(
'metadata',
models.JSONField(
blank=True,
help_text='JSON metadata field, for use by external plugins',
null=True,
verbose_name='Plugin Metadata',
),
),
(
'notes',
InvenTree.fields.InvenTreeNotesField(
blank=True,
help_text='Markdown notes (optional)',
max_length=50000,
null=True,
verbose_name='Notes',
),
),
(
'reference',
models.CharField(
help_text='Repair Order Reference',
max_length=100,
unique=True,
verbose_name='Reference',
),
),
(
'description',
models.CharField(
help_text='Repair order description',
max_length=250,
verbose_name='Description',
),
),
(
'symptoms',
models.TextField(
blank=True,
help_text='Reported symptoms or issues',
verbose_name='Symptoms',
),
),
(
'status',
models.IntegerField(
choices=[
(10, 'Pending'),
(20, 'In Progress'),
(25, 'On Hold'),
(30, 'Complete'),
(40, 'Cancelled'),
],
default=10,
help_text='Repair order status',
verbose_name='Status',
),
),
(
'customer',
models.ForeignKey(
blank=True,
help_text='Customer reference',
limit_choices_to={'is_customer': True},
null=True,
on_delete=django.db.models.deletion.SET_NULL,
related_name='repair_orders',
to='company.company',
verbose_name='Customer',
),
),
],
options={'verbose_name': 'Repair Order'},
bases=(
InvenTree.models.InvenTreeAttachmentMixin,
InvenTree.models.InvenTreePermissionCheckMixin,
InvenTree.models.ContentTypeMixin,
InvenTree.models.PluginValidationMixin,
models.Model,
),
),
migrations.CreateModel(
name='RepairOrderLineItem',
fields=[
(
'id',
models.AutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name='ID',
),
),
(
'metadata',
models.JSONField(
blank=True,
help_text='JSON metadata field, for use by external plugins',
null=True,
verbose_name='Plugin Metadata',
),
),
(
'order',
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name='lines',
to='order.repairorder',
verbose_name='Repair Order',
),
),
(
'part',
models.ForeignKey(
blank=True,
help_text='Part to be consumed for repair',
null=True,
on_delete=django.db.models.deletion.SET_NULL,
related_name='repair_order_line_items',
to='part.part',
verbose_name='Part',
),
),
(
'quantity',
models.DecimalField(
decimal_places=5,
default=1,
help_text='Item quantity required for repair',
max_digits=15,
verbose_name='Quantity',
),
),
],
options={'verbose_name': 'Repair Order Line Item'},
bases=(
InvenTree.models.ContentTypeMixin,
InvenTree.models.PluginValidationMixin,
models.Model,
),
),
migrations.CreateModel(
name='RepairOrderAllocation',
fields=[
(
'id',
models.AutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name='ID',
),
),
(
'line',
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name='allocations',
to='order.repairorderlineitem',
verbose_name='Line Item',
),
),
(
'item',
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name='repair_order_allocations',
to='stock.stockitem',
verbose_name='Stock Item',
),
),
(
'quantity',
models.DecimalField(
decimal_places=5,
default=1,
help_text='Allocated stock quantity',
max_digits=15,
verbose_name='Quantity',
),
),
],
options={'verbose_name': 'Repair Order Allocation'},
),
]
Loading
Loading