mirror of
https://github.com/inventree/InvenTree.git
synced 2026-09-28 22:55:42 +00:00
PO status fix (#12885)
* Fix for PurchaseOrder status code view - Order dependent, due to new viewset * Add regression tests for status code API endpoints
This commit is contained in:
@@ -1426,6 +1426,21 @@ class BuildListTest(BuildAPITest):
|
|||||||
assert_fnc=lambda x: x.data['results'][0],
|
assert_fnc=lambda x: x.data['results'][0],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_status_codes_endpoint(self):
|
||||||
|
"""The 'build/status/' endpoint must resolve to the status-codes view.
|
||||||
|
|
||||||
|
Regression test: ensures the literal 'status/' path is not shadowed by the
|
||||||
|
'build/<pk>/' detail route it sits alongside in the same urlconf.
|
||||||
|
"""
|
||||||
|
response = self.get(reverse('api-build-status-codes'), expected_code=200)
|
||||||
|
|
||||||
|
self.assertIn('status_class', response.data)
|
||||||
|
self.assertIn('values', response.data)
|
||||||
|
self.assertIn('PENDING', response.data['values'])
|
||||||
|
self.assertEqual(
|
||||||
|
response.data['values']['PENDING']['key'], BuildStatus.PENDING.value
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class BuildOutputCreateTest(BuildAPITest):
|
class BuildOutputCreateTest(BuildAPITest):
|
||||||
"""Unit test for creating build output via API."""
|
"""Unit test for creating build output via API."""
|
||||||
|
|||||||
@@ -2695,8 +2695,6 @@ class OrderCalendarExport(ICalFeed):
|
|||||||
|
|
||||||
|
|
||||||
order_api_urls = [
|
order_api_urls = [
|
||||||
# Purchase Order, Line Item, and Extra Line API endpoints via ViewSet router
|
|
||||||
path('', include(order_router.urls)),
|
|
||||||
# Purchase order status code information (requires custom kwargs)
|
# Purchase order status code information (requires custom kwargs)
|
||||||
path(
|
path(
|
||||||
'po/status/',
|
'po/status/',
|
||||||
@@ -2704,6 +2702,8 @@ order_api_urls = [
|
|||||||
{StatusView.MODEL_REF: PurchaseOrderStatus},
|
{StatusView.MODEL_REF: PurchaseOrderStatus},
|
||||||
name='api-po-status-codes',
|
name='api-po-status-codes',
|
||||||
),
|
),
|
||||||
|
# Purchase Order, Line Item, and Extra Line API endpoints via ViewSet router
|
||||||
|
path('', include(order_router.urls)),
|
||||||
# API endpoints for sales orders
|
# API endpoints for sales orders
|
||||||
path(
|
path(
|
||||||
'so/',
|
'so/',
|
||||||
|
|||||||
@@ -999,6 +999,27 @@ class PurchaseOrderTest(OrderTest):
|
|||||||
self.assertIn('status_text', result)
|
self.assertIn('status_text', result)
|
||||||
self.assertIsNotNone(result['status_text'])
|
self.assertIsNotNone(result['status_text'])
|
||||||
|
|
||||||
|
def test_status_codes_endpoint(self):
|
||||||
|
"""The 'po/status/' endpoint must resolve to the status-codes view.
|
||||||
|
|
||||||
|
Regression test: PurchaseOrder is served by a ViewSet router, whose
|
||||||
|
generated detail route ('po/<pk>/') uses DRF's default, permissive pk
|
||||||
|
lookup regex. That regex is happy to match the literal segment 'status'
|
||||||
|
as a pk, so if the router is registered ahead of the 'po/status/' path in
|
||||||
|
the urlconf, this endpoint gets swallowed by
|
||||||
|
PurchaseOrderViewSet.retrieve(pk='status') instead of reaching StatusView -
|
||||||
|
returning a 404 (no such PurchaseOrder) rather than the status code data.
|
||||||
|
"""
|
||||||
|
response = self.get(reverse('api-po-status-codes'), expected_code=200)
|
||||||
|
|
||||||
|
# A genuine StatusView response - not a PurchaseOrder-detail-shaped 404
|
||||||
|
self.assertIn('status_class', response.data)
|
||||||
|
self.assertIn('values', response.data)
|
||||||
|
self.assertIn('PENDING', response.data['values'])
|
||||||
|
self.assertEqual(
|
||||||
|
response.data['values']['PENDING']['key'], PurchaseOrderStatus.PENDING.value
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class PurchaseOrderLineItemTest(OrderTest):
|
class PurchaseOrderLineItemTest(OrderTest):
|
||||||
"""Unit tests for PurchaseOrderLineItems."""
|
"""Unit tests for PurchaseOrderLineItems."""
|
||||||
@@ -2489,6 +2510,25 @@ class SalesOrderTest(OrderTest):
|
|||||||
self.assertIn('status_text', result)
|
self.assertIn('status_text', result)
|
||||||
self.assertIsNotNone(result['status_text'])
|
self.assertIsNotNone(result['status_text'])
|
||||||
|
|
||||||
|
def test_status_codes_endpoint(self):
|
||||||
|
"""The 'so/status/' endpoint must resolve to the status-codes view.
|
||||||
|
|
||||||
|
SalesOrder is not (yet) served by a ViewSet router - its detail route uses
|
||||||
|
Django's '<int:pk>' path converter, which is not vulnerable to the
|
||||||
|
router-based bug affecting PurchaseOrder (see PurchaseOrderTest for
|
||||||
|
details). This is a coverage test guarding against a future regression,
|
||||||
|
e.g. if SalesOrder is migrated to a router-based viewset without also
|
||||||
|
restricting the pk lookup pattern.
|
||||||
|
"""
|
||||||
|
response = self.get(reverse('api-so-status-codes'), expected_code=200)
|
||||||
|
|
||||||
|
self.assertIn('status_class', response.data)
|
||||||
|
self.assertIn('values', response.data)
|
||||||
|
self.assertIn('PENDING', response.data['values'])
|
||||||
|
self.assertEqual(
|
||||||
|
response.data['values']['PENDING']['key'], SalesOrderStatus.PENDING.value
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class SalesOrderLineItemTest(OrderTest):
|
class SalesOrderLineItemTest(OrderTest):
|
||||||
"""Tests for the SalesOrderLineItem API."""
|
"""Tests for the SalesOrderLineItem API."""
|
||||||
@@ -3888,6 +3928,23 @@ class ReturnOrderTests(InvenTreeAPITestCase):
|
|||||||
reverse('api-return-order-detail', kwargs={'pk': 1}), ['customer_detail']
|
reverse('api-return-order-detail', kwargs={'pk': 1}), ['customer_detail']
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_status_codes_endpoint(self):
|
||||||
|
"""The 'ro/status/' endpoint must resolve to the status-codes view.
|
||||||
|
|
||||||
|
ReturnOrder is not (yet) served by a ViewSet router - its detail route uses
|
||||||
|
Django's '<int:pk>' path converter, which is not vulnerable to the
|
||||||
|
router-based bug affecting PurchaseOrder (see PurchaseOrderTest for
|
||||||
|
details). This is a coverage test guarding against a future regression.
|
||||||
|
"""
|
||||||
|
response = self.get(reverse('api-return-order-status-codes'), expected_code=200)
|
||||||
|
|
||||||
|
self.assertIn('status_class', response.data)
|
||||||
|
self.assertIn('values', response.data)
|
||||||
|
self.assertIn('PENDING', response.data['values'])
|
||||||
|
self.assertEqual(
|
||||||
|
response.data['values']['PENDING']['key'], ReturnOrderStatus.PENDING.value
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class ReturnOrderLineItemTests(InvenTreeAPITestCase):
|
class ReturnOrderLineItemTests(InvenTreeAPITestCase):
|
||||||
"""Unit tests for ReturnOrderLineItem API endpoints."""
|
"""Unit tests for ReturnOrderLineItem API endpoints."""
|
||||||
@@ -4051,6 +4108,26 @@ class ReturnOrderLineItemTests(InvenTreeAPITestCase):
|
|||||||
|
|
||||||
self.assertEqual(models.ReturnOrderExtraLine.objects.count(), n - 2)
|
self.assertEqual(models.ReturnOrderExtraLine.objects.count(), n - 2)
|
||||||
|
|
||||||
|
def test_status_codes_endpoint(self):
|
||||||
|
"""The 'ro-line/status/' endpoint must resolve to the status-codes view.
|
||||||
|
|
||||||
|
ReturnOrderLineItem is not (yet) served by a ViewSet router - its detail
|
||||||
|
route uses Django's '<int:pk>' path converter, which is not vulnerable to
|
||||||
|
the router-based bug affecting PurchaseOrder (see PurchaseOrderTest for
|
||||||
|
details). This is a coverage test guarding against a future regression.
|
||||||
|
"""
|
||||||
|
response = self.get(
|
||||||
|
reverse('api-return-order-line-status-codes'), expected_code=200
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertIn('status_class', response.data)
|
||||||
|
self.assertIn('values', response.data)
|
||||||
|
self.assertIn('PENDING', response.data['values'])
|
||||||
|
self.assertEqual(
|
||||||
|
response.data['values']['PENDING']['key'],
|
||||||
|
ReturnOrderLineStatus.PENDING.value,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class ExtraLineTotalPriceTest(InvenTreeAPITestCase):
|
class ExtraLineTotalPriceTest(InvenTreeAPITestCase):
|
||||||
"""Unit tests for the 'total_price' field on ExtraLine API endpoints.
|
"""Unit tests for the 'total_price' field on ExtraLine API endpoints.
|
||||||
|
|||||||
@@ -2417,6 +2417,19 @@ class StockItemTest(StockAPITestCase):
|
|||||||
item.refresh_from_db()
|
item.refresh_from_db()
|
||||||
self.assertEqual(item.batch, 'NEW-BATCH-CODE')
|
self.assertEqual(item.batch, 'NEW-BATCH-CODE')
|
||||||
|
|
||||||
|
def test_status_codes_endpoint(self):
|
||||||
|
"""The 'stock/status/' endpoint must resolve to the status-codes view.
|
||||||
|
|
||||||
|
Regression test: ensures the literal 'status/' path is not shadowed by the
|
||||||
|
'stock/<pk>/' detail route it sits alongside in the same urlconf.
|
||||||
|
"""
|
||||||
|
response = self.get(reverse('api-stock-status-codes'), expected_code=200)
|
||||||
|
|
||||||
|
self.assertIn('status_class', response.data)
|
||||||
|
self.assertIn('values', response.data)
|
||||||
|
self.assertIn('OK', response.data['values'])
|
||||||
|
self.assertEqual(response.data['values']['OK']['key'], StockStatus.OK.value)
|
||||||
|
|
||||||
|
|
||||||
class StockItemDisassembleTest(StockAPITestCase):
|
class StockItemDisassembleTest(StockAPITestCase):
|
||||||
"""Series of API tests for the StockItem disassembly endpoint."""
|
"""Series of API tests for the StockItem disassembly endpoint."""
|
||||||
@@ -4051,6 +4064,23 @@ class StockTrackingTest(StockAPITestCase):
|
|||||||
assert_fnc=lambda x: x.data['results'][0],
|
assert_fnc=lambda x: x.data['results'][0],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_status_codes_endpoint(self):
|
||||||
|
"""The 'track/status/' endpoint must resolve to the status-codes view.
|
||||||
|
|
||||||
|
Regression test: ensures the literal 'status/' path is not shadowed by the
|
||||||
|
'track/<pk>/' detail route it sits alongside in the same urlconf.
|
||||||
|
"""
|
||||||
|
response = self.get(
|
||||||
|
reverse('api-stock-tracking-status-codes'), expected_code=200
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertIn('status_class', response.data)
|
||||||
|
self.assertIn('values', response.data)
|
||||||
|
self.assertIn('CREATED', response.data['values'])
|
||||||
|
self.assertEqual(
|
||||||
|
response.data['values']['CREATED']['key'], StockHistoryCode.CREATED.value
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class StockAssignTest(StockAPITestCase):
|
class StockAssignTest(StockAPITestCase):
|
||||||
"""Unit tests for the stock assignment API endpoint, where stock items are manually assigned to a customer."""
|
"""Unit tests for the stock assignment API endpoint, where stock items are manually assigned to a customer."""
|
||||||
|
|||||||
Reference in New Issue
Block a user