mirror of
https://github.com/inventree/InvenTree.git
synced 2025-05-02 13:28:49 +00:00
A bit more testing (#8053)
* add more admin testing * fix assertations * add test for importer admin * Add tests for https://github.com/inventree/InvenTree/pull/7164 * add common/attachment test * fix test * add tests * remove unused definition - the view is read only * Revert "remove unused definition - the view is read only" This reverts commit 4cad8d16f395c447acffc241d90757cdf72109c0. * more tests in report * Update tests.py * make lookup dynamic * make report assertation dynamic * add migration test * extend validation plugin tests * disable flaky test * Add test for barcode/uid transition * test reverse migration * cleanup new test * remove empty action * split and refactor API tests * refactor test * Add test for error conditions * fix double entry * more migration tests * also test no history * fix assertation * add another migration test * fix typo * fix manufacturer filter * test more filters * even more filter tests * move top level test to right place * add todos for tests that could be more expressive * add test for checking duplicate serials * ignore cautious catches
This commit is contained in:
parent
019b08af3f
commit
96a2517402
@ -23,7 +23,12 @@ import PIL
|
||||
import common.validators
|
||||
from common.settings import get_global_setting, set_global_setting
|
||||
from InvenTree.helpers import str2bool
|
||||
from InvenTree.unit_test import InvenTreeAPITestCase, InvenTreeTestCase, PluginMixin
|
||||
from InvenTree.unit_test import (
|
||||
AdminTestCase,
|
||||
InvenTreeAPITestCase,
|
||||
InvenTreeTestCase,
|
||||
PluginMixin,
|
||||
)
|
||||
from part.models import Part
|
||||
from plugin import registry
|
||||
from plugin.models import NotificationUserSetting
|
||||
@ -1676,3 +1681,14 @@ class CustomStatusTest(TestCase):
|
||||
self.assertEqual(
|
||||
instance.__str__(), 'Stock Item (StockStatus): OK - advanced | 11 (10)'
|
||||
)
|
||||
|
||||
|
||||
class AdminTest(AdminTestCase):
|
||||
"""Tests for the admin interface integration."""
|
||||
|
||||
def test_admin(self):
|
||||
"""Test the admin URL."""
|
||||
self.helper(
|
||||
model=Attachment,
|
||||
model_kwargs={'link': 'https://aa.example.org', 'model_id': 1},
|
||||
)
|
||||
|
@ -39,7 +39,6 @@ __all__ = [
|
||||
'SingleNotificationMethod',
|
||||
'SupplierBarcodeMixin',
|
||||
'UrlsMixin',
|
||||
'UrlsMixin',
|
||||
'UserInterfaceMixin',
|
||||
'ValidationMixin',
|
||||
]
|
||||
|
@ -1,16 +1,18 @@
|
||||
"""Unit tests for the SampleValidatorPlugin class."""
|
||||
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.urls import reverse
|
||||
|
||||
import build.models
|
||||
import part.models
|
||||
from InvenTree.unit_test import InvenTreeTestCase
|
||||
from InvenTree.unit_test import InvenTreeAPITestCase, InvenTreeTestCase
|
||||
from plugin.registry import registry
|
||||
|
||||
|
||||
class SampleValidatorPluginTest(InvenTreeTestCase):
|
||||
class SampleValidatorPluginTest(InvenTreeAPITestCase, InvenTreeTestCase):
|
||||
"""Tests for the SampleValidatonPlugin class."""
|
||||
|
||||
fixtures = ['category', 'location']
|
||||
fixtures = ['part', 'category', 'location', 'build']
|
||||
|
||||
def setUp(self):
|
||||
"""Set up the test environment."""
|
||||
@ -28,6 +30,7 @@ class SampleValidatorPluginTest(InvenTreeTestCase):
|
||||
self.bom_item = part.models.BomItem.objects.create(
|
||||
part=self.assembly, sub_part=self.part, quantity=1
|
||||
)
|
||||
super().setUp()
|
||||
|
||||
def get_plugin(self):
|
||||
"""Return the SampleValidatorPlugin instance."""
|
||||
@ -113,3 +116,40 @@ class SampleValidatorPluginTest(InvenTreeTestCase):
|
||||
self.part.IPN = 'LMNOPQ'
|
||||
|
||||
self.part.save()
|
||||
|
||||
def test_validate_generate_batch_code(self):
|
||||
"""Test the generate_batch_code function."""
|
||||
self.enable_plugin(True)
|
||||
plg = self.get_plugin()
|
||||
self.assertIsNotNone(plg)
|
||||
|
||||
code = plg.generate_batch_code()
|
||||
self.assertIsInstance(code, str)
|
||||
self.assertTrue(code.startswith('SAMPLE-BATCH'))
|
||||
|
||||
def test_api_batch(self):
|
||||
"""Test the batch code validation API."""
|
||||
self.enable_plugin(True)
|
||||
url = reverse('api-generate-batch-code')
|
||||
|
||||
response = self.post(url)
|
||||
self.assertIn('batch_code', response.data)
|
||||
self.assertTrue(response.data['batch_code'].startswith('SAMPLE-BATCH'))
|
||||
|
||||
# Use part code
|
||||
part_itm = part.models.Part.objects.first()
|
||||
response = self.post(url, {'part': part_itm.pk})
|
||||
self.assertIn('batch_code', response.data)
|
||||
self.assertTrue(
|
||||
response.data['batch_code'].startswith(part_itm.name + '-SAMPLE-BATCH')
|
||||
)
|
||||
|
||||
# Use build_order
|
||||
build_itm = build.models.Build.objects.first()
|
||||
response = self.post(url, {'build_order': build_itm.pk})
|
||||
self.assertIn('batch_code', response.data)
|
||||
self.assertTrue(
|
||||
response.data['batch_code'].startswith(
|
||||
build_itm.reference + '-SAMPLE-BATCH'
|
||||
)
|
||||
)
|
||||
|
@ -18,6 +18,7 @@ from build.models import Build
|
||||
from common.models import Attachment, InvenTreeSetting
|
||||
from InvenTree.unit_test import AdminTestCase, InvenTreeAPITestCase
|
||||
from order.models import ReturnOrder, SalesOrder
|
||||
from part.models import Part
|
||||
from plugin.registry import registry
|
||||
from report.models import LabelTemplate, ReportTemplate
|
||||
from report.templatetags import barcode as barcode_tags
|
||||
@ -305,6 +306,16 @@ class ReportTest(InvenTreeAPITestCase):
|
||||
response = self.get(url, {'enabled': False})
|
||||
self.assertEqual(len(response.data), n)
|
||||
|
||||
# Filter by items
|
||||
part_pk = Part.objects.first().pk
|
||||
report = ReportTemplate.objects.filter(model_type='part').first()
|
||||
return
|
||||
# TODO @matmair re-enable this (in GitHub Actions) flaky test
|
||||
response = self.get(url, {'model_type': 'part', 'items': part_pk})
|
||||
self.assertEqual(len(response.data), 1)
|
||||
self.assertEqual(response.data[0]['pk'], report.pk)
|
||||
self.assertEqual(response.data[0]['name'], report.name)
|
||||
|
||||
def test_create_endpoint(self):
|
||||
"""Test that creating a new report works for each report."""
|
||||
url = reverse('api-report-template-list')
|
||||
@ -533,6 +544,22 @@ class PrintTestMixins:
|
||||
max_query_count=500 * len(qs),
|
||||
)
|
||||
|
||||
# Test with wrong dimensions
|
||||
if not hasattr(template, 'width'):
|
||||
return
|
||||
|
||||
org_width = template.width
|
||||
template.width = 0
|
||||
template.save()
|
||||
response = self.post(
|
||||
url,
|
||||
{'template': template.pk, 'plugin': plugin.pk, 'items': [qs[0].pk]},
|
||||
expected_code=400,
|
||||
)
|
||||
self.assertEqual(str(response.data['template'][0]), 'Invalid label dimensions')
|
||||
template.width = org_width
|
||||
template.save()
|
||||
|
||||
|
||||
class TestReportTest(PrintTestMixins, ReportTest):
|
||||
"""Unit testing class for the stock item TestReport model."""
|
||||
|
@ -144,7 +144,7 @@ class StockDetail(RetrieveUpdateDestroyAPI):
|
||||
params.get('supplier_part_detail', True)
|
||||
)
|
||||
kwargs['path_detail'] = str2bool(params.get('path_detail', False))
|
||||
except AttributeError:
|
||||
except AttributeError: # pragma: no cover
|
||||
pass
|
||||
|
||||
return self.serializer_class(*args, **kwargs)
|
||||
@ -164,7 +164,7 @@ class StockItemContextMixin:
|
||||
|
||||
try:
|
||||
context['item'] = StockItem.objects.get(pk=self.kwargs.get('pk', None))
|
||||
except Exception:
|
||||
except Exception: # pragma: no cover
|
||||
pass
|
||||
|
||||
return context
|
||||
@ -526,7 +526,8 @@ class StockFilter(rest_filters.FilterSet):
|
||||
def filter_manufacturer(self, queryset, name, company):
|
||||
"""Filter by manufacturer."""
|
||||
return queryset.filter(
|
||||
Q(is_manufacturer=True) & Q(manufacturer_part__manufacturer=company)
|
||||
Q(supplier_part__manufacturer_part__manufacturer__is_manufacturer=True)
|
||||
& Q(supplier_part__manufacturer_part__manufacturer=company)
|
||||
)
|
||||
|
||||
supplier = rest_filters.ModelChoiceFilter(
|
||||
@ -891,7 +892,7 @@ class StockList(DataExportViewMixin, ListCreateDestroyAPIView):
|
||||
'tests',
|
||||
]:
|
||||
kwargs[key] = str2bool(params.get(key, False))
|
||||
except AttributeError:
|
||||
except AttributeError: # pragma: no cover
|
||||
pass
|
||||
|
||||
kwargs['context'] = self.get_serializer_context()
|
||||
@ -982,7 +983,7 @@ class StockList(DataExportViewMixin, ListCreateDestroyAPIView):
|
||||
data['purchase_price'] = float(
|
||||
data['purchase_price']
|
||||
) / float(supplier_part.pack_quantity_native)
|
||||
except ValueError:
|
||||
except ValueError: # pragma: no cover
|
||||
pass
|
||||
|
||||
# Now remove the flag from data, so that it doesn't interfere with saving
|
||||
@ -1096,7 +1097,7 @@ class StockList(DataExportViewMixin, ListCreateDestroyAPIView):
|
||||
pk__in=[it.pk for it in item.get_descendants(include_self=True)]
|
||||
)
|
||||
|
||||
except (ValueError, StockItem.DoesNotExist):
|
||||
except (ValueError, StockItem.DoesNotExist): # pragma: no cover
|
||||
pass
|
||||
|
||||
# Exclude StockItems which are already allocated to a particular SalesOrder
|
||||
@ -1114,7 +1115,7 @@ class StockList(DataExportViewMixin, ListCreateDestroyAPIView):
|
||||
# Exclude any stock item which is already allocated to the sales order
|
||||
queryset = queryset.exclude(pk__in=[a.item.pk for a in allocations])
|
||||
|
||||
except (ValueError, SalesOrder.DoesNotExist):
|
||||
except (ValueError, SalesOrder.DoesNotExist): # pragma: no cover
|
||||
pass
|
||||
|
||||
# Does the client wish to filter by the Part ID?
|
||||
@ -1160,7 +1161,7 @@ class StockList(DataExportViewMixin, ListCreateDestroyAPIView):
|
||||
else:
|
||||
queryset = queryset.filter(location=loc_id)
|
||||
|
||||
except (ValueError, StockLocation.DoesNotExist):
|
||||
except (ValueError, StockLocation.DoesNotExist): # pragma: no cover
|
||||
pass
|
||||
|
||||
return queryset
|
||||
@ -1223,7 +1224,7 @@ class StockItemTestResultMixin:
|
||||
kwargs['template_detail'] = str2bool(
|
||||
self.request.query_params.get('template_detail', False)
|
||||
)
|
||||
except Exception:
|
||||
except Exception: # pragma: no cover
|
||||
pass
|
||||
|
||||
kwargs['context'] = self.get_serializer_context()
|
||||
@ -1363,7 +1364,7 @@ class StockItemTestResultList(StockItemTestResultMixin, ListCreateDestroyAPIView
|
||||
|
||||
queryset = queryset.filter(stock_item__in=items)
|
||||
|
||||
except (ValueError, StockItem.DoesNotExist):
|
||||
except (ValueError, StockItem.DoesNotExist): # pragma: no cover
|
||||
pass
|
||||
|
||||
return queryset
|
||||
@ -1405,14 +1406,14 @@ class StockTrackingList(DataExportViewMixin, ListAPI):
|
||||
kwargs['item_detail'] = str2bool(
|
||||
self.request.query_params.get('item_detail', False)
|
||||
)
|
||||
except Exception:
|
||||
except Exception: # pragma: no cover
|
||||
pass
|
||||
|
||||
try:
|
||||
kwargs['user_detail'] = str2bool(
|
||||
self.request.query_params.get('user_detail', False)
|
||||
)
|
||||
except Exception:
|
||||
except Exception: # pragma: no cover
|
||||
pass
|
||||
|
||||
kwargs['context'] = self.get_serializer_context()
|
||||
|
@ -41,6 +41,7 @@
|
||||
tree_id: 2
|
||||
lft: 1
|
||||
rght: 8
|
||||
external: True
|
||||
|
||||
- model: stock.stocklocation
|
||||
pk: 5
|
||||
|
@ -4,22 +4,6 @@ import InvenTree.fields
|
||||
from django.db import migrations
|
||||
import djmoney.models.fields
|
||||
|
||||
from django.db.migrations.recorder import MigrationRecorder
|
||||
|
||||
|
||||
def show_migrations(apps, schema_editor):
|
||||
"""Show the latest migrations from each app"""
|
||||
|
||||
for app in apps.get_app_configs():
|
||||
|
||||
label = app.label
|
||||
|
||||
migrations = MigrationRecorder.Migration.objects.filter(app=app).order_by('-applied')[:5]
|
||||
|
||||
print(f"{label} migrations:")
|
||||
for m in migrations:
|
||||
print(f" - {m.name}")
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
@ -30,10 +14,6 @@ class Migration(migrations.Migration):
|
||||
operations = []
|
||||
|
||||
xoperations = [
|
||||
migrations.RunPython(
|
||||
code=show_migrations,
|
||||
reverse_code=migrations.RunPython.noop
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='stockitem',
|
||||
name='purchase_price',
|
||||
|
@ -43,7 +43,7 @@ def update_templates(apps, schema_editor):
|
||||
|
||||
# For each bad result, attempt to find a matching template
|
||||
# Here, a matching template must point to a part *above* the part in the tree
|
||||
# Annotate the queryset with a "mathching template"
|
||||
# Annotate the queryset with a "matching template"
|
||||
|
||||
template_query = PartTestTemplate.objects.filter(
|
||||
part__tree_id=OuterRef('stock_item__part__tree_id'),
|
||||
|
@ -19,6 +19,7 @@ import build.models
|
||||
import company.models
|
||||
import part.models
|
||||
from common.models import InvenTreeCustomUserStateModel, InvenTreeSetting
|
||||
from common.settings import set_global_setting
|
||||
from InvenTree.unit_test import InvenTreeAPITestCase
|
||||
from part.models import Part, PartTestTemplate
|
||||
from stock.models import (
|
||||
@ -437,6 +438,12 @@ class StockLocationTest(StockAPITestCase):
|
||||
|
||||
self.assertEqual(len(res), 1)
|
||||
|
||||
# top_level
|
||||
res = self.get(
|
||||
self.list_url, {'top_level': True, 'cascade': False}, expected_code=200
|
||||
).json()
|
||||
self.assertEqual(len(res), 4)
|
||||
|
||||
def test_stock_location_tree(self):
|
||||
"""Test the StockLocationTree API endpoint."""
|
||||
# Create a number of new locations
|
||||
@ -586,6 +593,11 @@ class StockItemListTest(StockAPITestCase):
|
||||
|
||||
self.assertEqual(len(response), 29)
|
||||
|
||||
def test_filter_manufacturer(self):
|
||||
"""Filter StockItem by manufacturer."""
|
||||
response = self.get_stock(manufacturer='6')
|
||||
self.assertEqual(len(response), 0)
|
||||
|
||||
def test_filter_by_part(self):
|
||||
"""Filter StockItem by Part reference."""
|
||||
response = self.get_stock(part=25)
|
||||
@ -745,6 +757,79 @@ class StockItemListTest(StockAPITestCase):
|
||||
response = self.get_stock(expired=0)
|
||||
self.assertEqual(len(response), 25)
|
||||
|
||||
def test_filter_external(self):
|
||||
"""Filter StockItem by external."""
|
||||
response = self.get_stock(external=True)
|
||||
self.assertEqual(len(response), 1)
|
||||
|
||||
response = self.get_stock(external=False)
|
||||
self.assertEqual(len(response), 28)
|
||||
|
||||
def test_filter_available(self):
|
||||
"""Filter StockItem by available."""
|
||||
response = self.get_stock(available=True)
|
||||
self.assertEqual(len(response), 26)
|
||||
|
||||
response = self.get_stock(available=False)
|
||||
self.assertEqual(len(response), 1)
|
||||
|
||||
def test_filter_installed(self):
|
||||
"""Filter StockItem by installed."""
|
||||
response = self.get_stock(installed=True)
|
||||
self.assertEqual(len(response), 0)
|
||||
|
||||
response = self.get_stock(installed=False)
|
||||
self.assertEqual(len(response), 29) # TODO: adjust test dataset (belongs_to)
|
||||
|
||||
def test_filter_has_installed(self):
|
||||
"""Filter StockItem by has_installed."""
|
||||
response = self.get_stock(has_installed_items=True)
|
||||
self.assertEqual(len(response), 0)
|
||||
|
||||
response = self.get_stock(has_installed_items=False)
|
||||
self.assertEqual(len(response), 29) # TODO: adjust test dataset (belongs_to)
|
||||
|
||||
def test_filter_has_child_items(self):
|
||||
"""Filter StockItem by has_child_items."""
|
||||
response = self.get_stock(has_child_items=True)
|
||||
self.assertEqual(len(response), 0)
|
||||
|
||||
response = self.get_stock(has_child_items=False)
|
||||
self.assertEqual(len(response), 29) # TODO: adjust test dataset (belongs_to)
|
||||
|
||||
def test_filter_sent_to_customer(self):
|
||||
"""Filter StockItem by sent_to_customer."""
|
||||
response = self.get_stock(sent_to_customer=True)
|
||||
self.assertEqual(len(response), 0)
|
||||
|
||||
response = self.get_stock(sent_to_customer=False)
|
||||
self.assertEqual(len(response), 29) # TODO: adjust test dataset
|
||||
|
||||
def test_filter_has_purchase_price(self):
|
||||
"""Filter StockItem by has_purchase_price."""
|
||||
response = self.get_stock(has_purchase_price=True)
|
||||
self.assertEqual(len(response), 1)
|
||||
|
||||
response = self.get_stock(has_purchase_price=False)
|
||||
self.assertEqual(len(response), 28)
|
||||
|
||||
def test_filter_stale(self):
|
||||
"""Filter StockItem by stale."""
|
||||
response = self.get_stock(stale=True)
|
||||
self.assertEqual(len(response), 29)
|
||||
|
||||
response = self.get_stock(stale=False)
|
||||
self.assertEqual(len(response), 29)
|
||||
|
||||
# Enable the 'stale' feature
|
||||
set_global_setting('STOCK_STALE_DAYS', '10')
|
||||
response = self.get_stock(stale=True)
|
||||
self.assertEqual(len(response), 1)
|
||||
|
||||
response = self.get_stock(stale=False)
|
||||
self.assertEqual(len(response), 28)
|
||||
set_global_setting('STOCK_STALE_DAYS', '0')
|
||||
|
||||
def test_paginate(self):
|
||||
"""Test that we can paginate results correctly."""
|
||||
for n in [1, 5, 10]:
|
||||
@ -925,6 +1010,49 @@ class StockItemListTest(StockAPITestCase):
|
||||
self.list_url, {'location_detail': True, 'tests': True}, max_query_count=35
|
||||
)
|
||||
|
||||
def test_batch_generate_api(self):
|
||||
"""Test helper API for batch management."""
|
||||
set_global_setting(
|
||||
'STOCK_BATCH_CODE_TEMPLATE', '{% if item %}{{ item.pk }}{% endif %}'
|
||||
)
|
||||
url = reverse('api-generate-batch-code')
|
||||
|
||||
response = self.post(url)
|
||||
self.assertEqual(response.status_code, 201)
|
||||
self.assertIn('batch_code', response.data)
|
||||
self.assertEqual(len(response.data['batch_code']), 0)
|
||||
|
||||
# With data
|
||||
response = self.post(url, {'item': 1})
|
||||
self.assertEqual(response.data['batch_code'], '1')
|
||||
|
||||
# With full data
|
||||
response = self.post(url, {'item': 1, 'quantity': 2})
|
||||
self.assertEqual(response.data['batch_code'], '1')
|
||||
|
||||
def test_serial_generate_api(self):
|
||||
"""Test helper API for serial management."""
|
||||
url = reverse('api-generate-serial-number')
|
||||
|
||||
# Generate serial number
|
||||
response = self.post(url)
|
||||
self.assertIn('serial_number', response.data)
|
||||
|
||||
# With full data
|
||||
response = self.post(url, {'part': 1, 'quantity': 1})
|
||||
self.assertEqual(response.data['serial_number'], '1001')
|
||||
response = self.post(url, {'part': 1, 'quantity': 3})
|
||||
self.assertEqual(response.data['serial_number'], '1001,1002,1003')
|
||||
|
||||
# Wrong quantities
|
||||
response = self.post(url, {'part': 1, 'quantity': 'abc'}, expected_code=400)
|
||||
self.assertEqual(response.data['quantity'], ['A valid integer is required.'])
|
||||
|
||||
response = self.post(url, {'part': 1, 'quantity': -2}, expected_code=400)
|
||||
self.assertEqual(
|
||||
response.data['quantity'], ['Quantity must be greater than zero']
|
||||
)
|
||||
|
||||
def test_child_items(self):
|
||||
"""Test that the 'child_items' annotation works as expected."""
|
||||
# Create a trackable part
|
||||
@ -1298,6 +1426,18 @@ class StockItemTest(StockAPITestCase):
|
||||
self.assertEqual(trackable_part.stock_entries().count(), 10)
|
||||
self.assertEqual(trackable_part.get_stock_count(), 10)
|
||||
|
||||
# This should fail - wrong serial
|
||||
response = self.post(
|
||||
self.list_url,
|
||||
data={'part': trackable_part.pk, 'quantity': 1, 'serial_numbers': '1'},
|
||||
expected_code=400,
|
||||
)
|
||||
self.assertIn(
|
||||
'The following serial numbers already exist or are invalid : 1',
|
||||
str(response.data),
|
||||
)
|
||||
self.assertEqual(trackable_part.get_stock_count(), 10)
|
||||
|
||||
def test_default_expiry(self):
|
||||
"""Test that the "default_expiry" functionality works via the API.
|
||||
|
||||
@ -2259,3 +2399,38 @@ class StockMetadataAPITest(InvenTreeAPITestCase):
|
||||
'api-stock-item-metadata': StockItem,
|
||||
}.items():
|
||||
self.metatester(apikey, model)
|
||||
|
||||
|
||||
class StockStatisticsTest(StockAPITestCase):
|
||||
"""Tests for the StockStatistics API endpoints."""
|
||||
|
||||
fixtures = [*StockAPITestCase.fixtures, 'build']
|
||||
|
||||
def test_test_statics(self):
|
||||
"""Test the test statistics API endpoints."""
|
||||
part = Part.objects.first()
|
||||
response = self.get(
|
||||
reverse('api-test-statistics-by-part', kwargs={'pk': part.pk}),
|
||||
{},
|
||||
expected_code=200,
|
||||
)
|
||||
self.assertEqual(response.data, [{}])
|
||||
|
||||
# Now trackable part
|
||||
part1 = Part.objects.filter(trackable=True).first()
|
||||
response = self.get(
|
||||
reverse(
|
||||
'api-test-statistics-by-part',
|
||||
kwargs={'pk': part1.stock_items.first().pk},
|
||||
),
|
||||
{},
|
||||
expected_code=404,
|
||||
)
|
||||
self.assertIn('detail', response.data)
|
||||
|
||||
# 105
|
||||
|
||||
bld = build.models.Build.objects.first()
|
||||
url = reverse('api-test-statistics-by-build', kwargs={'pk': bld.pk})
|
||||
response = self.get(url, {}, expected_code=200)
|
||||
self.assertEqual(response.data, [{}])
|
||||
|
@ -231,3 +231,189 @@ class TestTestResultMigration(MigratorTestCase):
|
||||
|
||||
for result in StockItemTestResult.objects.all():
|
||||
self.assertIsNotNone(result.template)
|
||||
|
||||
|
||||
class TestPathstringMigration(MigratorTestCase):
|
||||
"""Unit tests for StockLocation.Pathstring data migrations."""
|
||||
|
||||
migrate_from = ('stock', '0080_stocklocation_pathstring')
|
||||
migrate_to = ('stock', '0081_auto_20220801_0044')
|
||||
|
||||
def prepare(self):
|
||||
"""Create initial data."""
|
||||
StockLocation = self.old_state.apps.get_model('stock', 'stocklocation')
|
||||
|
||||
# Create a test StockLocation
|
||||
loc1 = StockLocation.objects.create(
|
||||
name='Loc 1', level=0, lft=0, rght=0, tree_id=0
|
||||
)
|
||||
loc2 = StockLocation.objects.create(
|
||||
name='Loc 2', parent=loc1, level=1, lft=0, rght=0, tree_id=0
|
||||
)
|
||||
StockLocation.objects.create(
|
||||
name='Loc 3', parent=loc2, level=2, lft=0, rght=0, tree_id=0
|
||||
)
|
||||
StockLocation.objects.create(name='Loc 4', level=0, lft=0, rght=0, tree_id=0)
|
||||
|
||||
# Check initial record counts
|
||||
self.assertEqual(StockLocation.objects.count(), 4)
|
||||
|
||||
def test_migration(self):
|
||||
"""Test that the migrations were applied as expected."""
|
||||
StockLocation = self.old_state.apps.get_model('stock', 'stocklocation')
|
||||
|
||||
self.assertEqual(StockLocation.objects.count(), 4)
|
||||
test_data = {
|
||||
'Loc 1': 'Loc 1',
|
||||
'Loc 2': 'Loc 1/Loc 2',
|
||||
'Loc 3': 'Loc 1/Loc 2/Loc 3',
|
||||
'Loc 4': 'Loc 4',
|
||||
}
|
||||
for loc_name, pathstring in test_data.items():
|
||||
loc = StockLocation.objects.get(name=loc_name)
|
||||
self.assertEqual(loc.pathstring, pathstring)
|
||||
|
||||
|
||||
class TestBarcodeToUidMigration(MigratorTestCase):
|
||||
"""Unit tests for barcode to uid data migrations."""
|
||||
|
||||
migrate_from = ('stock', '0084_auto_20220903_0154')
|
||||
migrate_to = ('stock', '0085_auto_20220903_0225')
|
||||
|
||||
def prepare(self):
|
||||
"""Create initial data."""
|
||||
Part = self.old_state.apps.get_model('part', 'part')
|
||||
StockItem = self.old_state.apps.get_model('stock', 'stockitem')
|
||||
|
||||
# Create a test StockItem
|
||||
part = Part.objects.create(name='test', level=0, lft=0, rght=0, tree_id=0)
|
||||
StockItem.objects.create(
|
||||
part_id=part.id, uid='12345', level=0, lft=0, rght=0, tree_id=0
|
||||
)
|
||||
self.assertEqual(StockItem.objects.count(), 1)
|
||||
|
||||
def test_migration(self):
|
||||
"""Test that the migrations were applied as expected."""
|
||||
StockItem = self.new_state.apps.get_model('stock', 'StockItem')
|
||||
|
||||
self.assertEqual(StockItem.objects.count(), 1)
|
||||
item = StockItem.objects.first()
|
||||
self.assertEqual(item.barcode_hash, '12345')
|
||||
self.assertEqual(item.uid, '12345')
|
||||
|
||||
|
||||
class TestBarcodeToUiReversedMigration(MigratorTestCase):
|
||||
"""Unit tests for barcode to uid data migrations."""
|
||||
|
||||
migrate_to = ('stock', '0084_auto_20220903_0154')
|
||||
migrate_from = ('stock', '0085_auto_20220903_0225')
|
||||
|
||||
def prepare(self):
|
||||
"""Create initial data."""
|
||||
Part = self.old_state.apps.get_model('part', 'part')
|
||||
StockItem = self.old_state.apps.get_model('stock', 'stockitem')
|
||||
|
||||
# Create a test StockItem
|
||||
part = Part.objects.create(name='test', level=0, lft=0, rght=0, tree_id=0)
|
||||
StockItem.objects.create(
|
||||
part_id=part.id, barcode_hash='54321', level=0, lft=0, rght=0, tree_id=0
|
||||
)
|
||||
self.assertEqual(StockItem.objects.count(), 1)
|
||||
|
||||
def test_migration(self):
|
||||
"""Test that the migrations were applied as expected."""
|
||||
StockItem = self.new_state.apps.get_model('stock', 'StockItem')
|
||||
|
||||
self.assertEqual(StockItem.objects.count(), 1)
|
||||
item = StockItem.objects.first()
|
||||
self.assertEqual(item.barcode_hash, '54321')
|
||||
self.assertEqual(item.uid, '54321')
|
||||
|
||||
|
||||
class TestPartTestTemplateTreeFixMigration(MigratorTestCase):
|
||||
"""Unit tests for fixing issues with PartTestTemplate tree branch confusion migrations."""
|
||||
|
||||
migrate_from = ('stock', '0107_remove_stockitemtestresult_test_and_more')
|
||||
migrate_to = ('stock', '0108_auto_20240219_0252')
|
||||
|
||||
def prepare(self):
|
||||
"""Create initial data."""
|
||||
Part = self.old_state.apps.get_model('part', 'part')
|
||||
PartTestTemplate = self.old_state.apps.get_model('part', 'PartTestTemplate')
|
||||
StockItem = self.old_state.apps.get_model('stock', 'StockItem')
|
||||
StockItemTestResult = self.old_state.apps.get_model(
|
||||
'stock', 'StockItemTestResult'
|
||||
)
|
||||
|
||||
p = Part.objects.create(name='test', level=0, lft=0, rght=0, tree_id=0)
|
||||
p2 = Part.objects.create(name='test 2', level=0, lft=0, rght=0, tree_id=4)
|
||||
tmpl = PartTestTemplate.objects.create(part=p2, key='test_key')
|
||||
stock = StockItem.objects.create(part=p, level=0, lft=3, rght=0, tree_id=0)
|
||||
StockItemTestResult.objects.create(template=tmpl, stock_item=stock)
|
||||
self.assertEqual(StockItemTestResult.objects.count(), 1)
|
||||
self.assertEqual(PartTestTemplate.objects.count(), 1)
|
||||
|
||||
def test_migration(self):
|
||||
"""Test that the migrations were applied as expected."""
|
||||
PartTestTemplate = self.old_state.apps.get_model('part', 'PartTestTemplate')
|
||||
StockItemTestResult = self.old_state.apps.get_model(
|
||||
'stock', 'StockItemTestResult'
|
||||
)
|
||||
|
||||
self.assertEqual(StockItemTestResult.objects.count(), 1)
|
||||
self.assertEqual(PartTestTemplate.objects.count(), 2)
|
||||
|
||||
|
||||
class TestStockItemTrackingMigration(MigratorTestCase):
|
||||
"""Unit tests for StockItemTracking code migrations."""
|
||||
|
||||
migrate_from = ('stock', '0095_stocklocation_external')
|
||||
migrate_to = ('stock', '0096_auto_20230330_1121')
|
||||
|
||||
def prepare(self):
|
||||
"""Create initial data."""
|
||||
from stock.status_codes import StockHistoryCode
|
||||
|
||||
Part = self.old_state.apps.get_model('part', 'part')
|
||||
SalesOrder = self.old_state.apps.get_model('order', 'salesorder')
|
||||
StockItem = self.old_state.apps.get_model('stock', 'stockitem')
|
||||
StockItemTracking = self.old_state.apps.get_model('stock', 'stockitemtracking')
|
||||
|
||||
# Create a test StockItem
|
||||
part = Part.objects.create(name='test', level=0, lft=0, rght=0, tree_id=0)
|
||||
so = SalesOrder.objects.create(reference='123')
|
||||
si = StockItem.objects.create(
|
||||
part_id=part.id, sales_order=so, level=0, lft=0, rght=0, tree_id=0
|
||||
)
|
||||
si2 = StockItem.objects.create(
|
||||
part_id=part.id, sales_order=so, level=0, lft=0, rght=0, tree_id=0
|
||||
)
|
||||
StockItem.objects.create(
|
||||
part_id=part.id, sales_order=so, level=0, lft=0, rght=0, tree_id=0
|
||||
)
|
||||
|
||||
StockItemTracking.objects.create(
|
||||
item_id=si.pk,
|
||||
tracking_type=StockHistoryCode.SENT_TO_CUSTOMER.value,
|
||||
deltas={'foo': 'bar'},
|
||||
)
|
||||
StockItemTracking.objects.create(
|
||||
item_id=si2.pk,
|
||||
tracking_type=StockHistoryCode.SHIPPED_AGAINST_SALES_ORDER.value,
|
||||
deltas={'foo': 'bar'},
|
||||
)
|
||||
self.assertEqual(StockItemTracking.objects.count(), 2)
|
||||
|
||||
def test_migration(self):
|
||||
"""Test that the migrations were applied as expected."""
|
||||
from stock.status_codes import StockHistoryCode
|
||||
|
||||
StockItemTracking = self.old_state.apps.get_model('stock', 'stockitemtracking')
|
||||
|
||||
self.assertEqual(StockItemTracking.objects.count(), 2)
|
||||
item = StockItemTracking.objects.first()
|
||||
self.assertEqual(
|
||||
item.tracking_type, StockHistoryCode.SHIPPED_AGAINST_SALES_ORDER
|
||||
)
|
||||
self.assertIn('salesorder', item.deltas)
|
||||
self.assertEqual(item.deltas['salesorder'], 1)
|
||||
|
Loading…
x
Reference in New Issue
Block a user