2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-04-28 19:46:46 +00:00
InvenTree/InvenTree/build/test_migrations.py
Matthias Mair faac6b6bf5
refactor: remove blank lines after docstring (#5736)
There shouldn't be any blank lines after the function docstring.
Remove the blank lines to fix this issue.

Co-authored-by: deepsource-autofix[bot] <62050782+deepsource-autofix[bot]@users.noreply.github.com>
2023-10-18 07:28:57 +11:00

287 lines
9.4 KiB
Python

"""Tests for the build model database migrations."""
from django_test_migrations.contrib.unittest_case import MigratorTestCase
from InvenTree import unit_test
class TestForwardMigrations(MigratorTestCase):
"""Test entire schema migration sequence for the build app."""
migrate_from = ('build', unit_test.getOldestMigrationFile('build'))
migrate_to = ('build', unit_test.getNewestMigrationFile('build'))
def prepare(self):
"""Create initial data!"""
Part = self.old_state.apps.get_model('part', 'part')
buildable_part = Part.objects.create(
name='Widget',
description='Buildable Part',
active=True,
level=0, lft=0, rght=0, tree_id=0,
)
Build = self.old_state.apps.get_model('build', 'build')
Build.objects.create(
part=buildable_part,
title='A build of some stuff',
quantity=50,
)
def test_items_exist(self):
"""Test to ensure that the 'assembly' field is correctly configured"""
Part = self.new_state.apps.get_model('part', 'part')
self.assertEqual(Part.objects.count(), 1)
Build = self.new_state.apps.get_model('build', 'build')
self.assertEqual(Build.objects.count(), 1)
# Check that the part object now has an assembly field
part = Part.objects.all().first()
part.assembly = True
part.save()
part.assembly = False
part.save()
class TestReferenceMigration(MigratorTestCase):
"""Test custom migration which adds 'reference' field to Build model."""
migrate_from = ('build', unit_test.getOldestMigrationFile('build'))
migrate_to = ('build', '0018_build_reference')
def prepare(self):
"""Create some builds."""
Part = self.old_state.apps.get_model('part', 'part')
part = Part.objects.create(
name='Part',
description='A test part',
level=0, lft=0, rght=0, tree_id=0,
)
Build = self.old_state.apps.get_model('build', 'build')
Build.objects.create(
part=part,
title='My very first build',
quantity=10
)
Build.objects.create(
part=part,
title='My very second build',
quantity=10
)
Build.objects.create(
part=part,
title='My very third build',
quantity=10
)
# Ensure that the builds *do not* have a 'reference' field
for build in Build.objects.all():
with self.assertRaises(AttributeError):
print(build.reference)
def test_build_reference(self):
"""Test that the build reference is correctly assigned to the PK of the Build"""
Build = self.new_state.apps.get_model('build', 'build')
self.assertEqual(Build.objects.count(), 3)
# Check that the build reference is properly assigned
for build in Build.objects.all():
self.assertEqual(str(build.reference), str(build.pk))
class TestReferencePatternMigration(MigratorTestCase):
"""Unit test for data migration which converts reference to new format.
Ref: https://github.com/inventree/InvenTree/pull/3267
"""
migrate_from = ('build', '0019_auto_20201019_1302')
migrate_to = ('build', unit_test.getNewestMigrationFile('build'))
def prepare(self):
"""Create some initial data prior to migration"""
Setting = self.old_state.apps.get_model('common', 'inventreesetting')
# Create a custom existing prefix so we can confirm the operation is working
Setting.objects.create(
key='BUILDORDER_REFERENCE_PREFIX',
value='BuildOrder-',
)
Part = self.old_state.apps.get_model('part', 'part')
assembly = Part.objects.create(
name='Assy 1',
description='An assembly',
level=0, lft=0, rght=0, tree_id=0,
)
Build = self.old_state.apps.get_model('build', 'build')
for idx in range(1, 11):
Build.objects.create(
part=assembly,
title=f"Build {idx}",
quantity=idx,
reference=f"{idx + 100}",
level=0, lft=0, rght=0, tree_id=0,
)
def test_reference_migration(self):
"""Test that the reference fields have been correctly updated"""
Build = self.new_state.apps.get_model('build', 'build')
for build in Build.objects.all():
self.assertTrue(build.reference.startswith('BuildOrder-'))
Setting = self.new_state.apps.get_model('common', 'inventreesetting')
pattern = Setting.objects.get(key='BUILDORDER_REFERENCE_PATTERN')
self.assertEqual(pattern.value, 'BuildOrder-{ref:04d}')
class TestBuildLineCreation(MigratorTestCase):
"""Test that build lines are correctly created for existing builds.
Ref: https://github.com/inventree/InvenTree/pull/4855
This PR added the 'BuildLine' model, which acts as a link between a Build and a BomItem.
- Migration 0044 creates BuildLine objects for existing builds.
- Migration 0046 links any existing BuildItem objects to corresponding BuildLine
"""
migrate_from = ('build', '0041_alter_build_title')
migrate_to = ('build', '0047_auto_20230606_1058')
def prepare(self):
"""Create data to work with"""
# Model references
Part = self.old_state.apps.get_model('part', 'part')
BomItem = self.old_state.apps.get_model('part', 'bomitem')
Build = self.old_state.apps.get_model('build', 'build')
BuildItem = self.old_state.apps.get_model('build', 'builditem')
StockItem = self.old_state.apps.get_model('stock', 'stockitem')
# The "BuildLine" model does not exist yet
with self.assertRaises(LookupError):
self.old_state.apps.get_model('build', 'buildline')
# Create a part
assembly = Part.objects.create(
name='Assembly',
description='An assembly',
assembly=True,
level=0, lft=0, rght=0, tree_id=0,
)
# Create components
for idx in range(1, 11):
part = Part.objects.create(
name=f"Part {idx}",
description=f"Part {idx}",
level=0, lft=0, rght=0, tree_id=0,
)
# Create plentiful stock
StockItem.objects.create(
part=part,
quantity=1000,
level=0, lft=0, rght=0, tree_id=0,
)
# Create a BOM item
BomItem.objects.create(
part=assembly,
sub_part=part,
quantity=idx,
reference=f"REF-{idx}",
)
# Create some builds
for idx in range(1, 4):
build = Build.objects.create(
part=assembly,
title=f"Build {idx}",
quantity=idx * 10,
reference=f"REF-{idx}",
level=0, lft=0, rght=0, tree_id=0,
)
# Allocate stock to the build
for bom_item in BomItem.objects.all():
stock_item = StockItem.objects.get(part=bom_item.sub_part)
BuildItem.objects.create(
build=build,
bom_item=bom_item,
stock_item=stock_item,
quantity=bom_item.quantity,
)
def test_build_line_creation(self):
"""Test that the BuildLine objects have been created correctly"""
Build = self.new_state.apps.get_model('build', 'build')
BomItem = self.new_state.apps.get_model('part', 'bomitem')
BuildLine = self.new_state.apps.get_model('build', 'buildline')
BuildItem = self.new_state.apps.get_model('build', 'builditem')
StockItem = self.new_state.apps.get_model('stock', 'stockitem')
# There should be 3x builds
self.assertEqual(Build.objects.count(), 3)
# 10x BOMItem objects
self.assertEqual(BomItem.objects.count(), 10)
# 10x StockItem objects
self.assertEqual(StockItem.objects.count(), 10)
# And 30x BuildLine items (1 for each BomItem for each Build)
self.assertEqual(BuildLine.objects.count(), 30)
# And 30x BuildItem objects (1 for each BomItem for each Build)
self.assertEqual(BuildItem.objects.count(), 30)
# Check that each BuildItem has been linked to a BuildLine
for item in BuildItem.objects.all():
self.assertIsNotNone(item.build_line)
self.assertEqual(
item.stock_item.part,
item.build_line.bom_item.sub_part,
)
item = BuildItem.objects.first()
# Check that the "build" field has been removed
with self.assertRaises(AttributeError):
item.build
# Check that the "bom_item" field has been removed
with self.assertRaises(AttributeError):
item.bom_item
# Check that each BuildLine is correctly configured
for line in BuildLine.objects.all():
# Check that the quantity is correct
self.assertEqual(
line.quantity,
line.build.quantity * line.bom_item.quantity,
)
# Check that the linked parts are correct
self.assertEqual(
line.build.part,
line.bom_item.part,
)