mirror of
https://github.com/inventree/InvenTree.git
synced 2025-04-30 04:26:44 +00:00
Implement global settings for assembly and template values of Part model
This commit is contained in:
parent
9fa37a9156
commit
6c7b648133
@ -230,6 +230,9 @@ class EditPartForm(HelperForm):
|
|||||||
'default_supplier',
|
'default_supplier',
|
||||||
'units',
|
'units',
|
||||||
'minimum_stock',
|
'minimum_stock',
|
||||||
|
'component',
|
||||||
|
'assembly',
|
||||||
|
'is_template',
|
||||||
'trackable',
|
'trackable',
|
||||||
'purchaseable',
|
'purchaseable',
|
||||||
'salable',
|
'salable',
|
||||||
|
74
InvenTree/part/migrations/0061_auto_20210103_2306.py
Normal file
74
InvenTree/part/migrations/0061_auto_20210103_2306.py
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
# Generated by Django 3.0.7 on 2021-01-03 12:06
|
||||||
|
|
||||||
|
import InvenTree.fields
|
||||||
|
import InvenTree.validators
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
import mptt.fields
|
||||||
|
import part.settings
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('stock', '0055_auto_20201117_1453'),
|
||||||
|
('part', '0060_merge_20201112_1722'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='part',
|
||||||
|
name='IPN',
|
||||||
|
field=models.CharField(blank=True, help_text='Internal Part Number', max_length=100, null=True, validators=[InvenTree.validators.validate_part_ipn], verbose_name='IPN'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='part',
|
||||||
|
name='assembly',
|
||||||
|
field=models.BooleanField(default=part.settings.part_assembly_default, help_text='Can this part be built from other parts?', verbose_name='Assembly'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='part',
|
||||||
|
name='category',
|
||||||
|
field=mptt.fields.TreeForeignKey(blank=True, help_text='Part category', null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='parts', to='part.PartCategory', verbose_name='Category'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='part',
|
||||||
|
name='default_location',
|
||||||
|
field=mptt.fields.TreeForeignKey(blank=True, help_text='Where is this item normally stored?', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='default_parts', to='stock.StockLocation', verbose_name='Default Location'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='part',
|
||||||
|
name='description',
|
||||||
|
field=models.CharField(help_text='Part description', max_length=250, verbose_name='Description'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='part',
|
||||||
|
name='is_template',
|
||||||
|
field=models.BooleanField(default=part.settings.part_template_default, help_text='Is this part a template part?', verbose_name='Is Template'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='part',
|
||||||
|
name='keywords',
|
||||||
|
field=models.CharField(blank=True, help_text='Part keywords to improve visibility in search results', max_length=250, null=True, verbose_name='Keywords'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='part',
|
||||||
|
name='link',
|
||||||
|
field=InvenTree.fields.InvenTreeURLField(blank=True, help_text='Link to external URL', null=True, verbose_name='Link'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='part',
|
||||||
|
name='name',
|
||||||
|
field=models.CharField(help_text='Part name', max_length=100, validators=[InvenTree.validators.validate_part_name], verbose_name='Name'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='part',
|
||||||
|
name='revision',
|
||||||
|
field=models.CharField(blank=True, help_text='Part revision or version number', max_length=100, null=True, verbose_name='Revision'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='part',
|
||||||
|
name='variant_of',
|
||||||
|
field=models.ForeignKey(blank=True, help_text='Is this part a variant of another part?', limit_choices_to={'active': True, 'is_template': True}, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='variants', to='part.Part', verbose_name='Variant Of'),
|
||||||
|
),
|
||||||
|
]
|
@ -640,36 +640,69 @@ class Part(MPTTModel):
|
|||||||
parent_part.clean()
|
parent_part.clean()
|
||||||
parent_part.save()
|
parent_part.save()
|
||||||
|
|
||||||
name = models.CharField(max_length=100, blank=False,
|
name = models.CharField(
|
||||||
help_text=_('Part name'),
|
max_length=100, blank=False,
|
||||||
validators=[validators.validate_part_name]
|
help_text=_('Part name'),
|
||||||
)
|
verbose_name=_('Name'),
|
||||||
|
validators=[validators.validate_part_name]
|
||||||
|
)
|
||||||
|
|
||||||
is_template = models.BooleanField(default=False, help_text=_('Is this part a template part?'))
|
is_template = models.BooleanField(
|
||||||
|
default=part_settings.part_template_default,
|
||||||
|
verbose_name=_('Is Template'),
|
||||||
|
help_text=_('Is this part a template part?')
|
||||||
|
)
|
||||||
|
|
||||||
variant_of = models.ForeignKey('part.Part', related_name='variants',
|
variant_of = models.ForeignKey(
|
||||||
null=True, blank=True,
|
'part.Part', related_name='variants',
|
||||||
limit_choices_to={
|
null=True, blank=True,
|
||||||
'is_template': True,
|
limit_choices_to={
|
||||||
'active': True,
|
'is_template': True,
|
||||||
},
|
'active': True,
|
||||||
on_delete=models.SET_NULL,
|
},
|
||||||
help_text=_('Is this part a variant of another part?'))
|
on_delete=models.SET_NULL,
|
||||||
|
help_text=_('Is this part a variant of another part?'),
|
||||||
|
verbose_name=_('Variant Of'),
|
||||||
|
)
|
||||||
|
|
||||||
description = models.CharField(max_length=250, blank=False, help_text=_('Part description'))
|
description = models.CharField(
|
||||||
|
max_length=250, blank=False,
|
||||||
|
verbose_name=_('Description'),
|
||||||
|
help_text=_('Part description')
|
||||||
|
)
|
||||||
|
|
||||||
keywords = models.CharField(max_length=250, blank=True, null=True, help_text=_('Part keywords to improve visibility in search results'))
|
keywords = models.CharField(
|
||||||
|
max_length=250, blank=True, null=True,
|
||||||
|
verbose_name=_('Keywords'),
|
||||||
|
help_text=_('Part keywords to improve visibility in search results')
|
||||||
|
)
|
||||||
|
|
||||||
category = TreeForeignKey(PartCategory, related_name='parts',
|
category = TreeForeignKey(
|
||||||
null=True, blank=True,
|
PartCategory, related_name='parts',
|
||||||
on_delete=models.DO_NOTHING,
|
null=True, blank=True,
|
||||||
help_text=_('Part category'))
|
on_delete=models.DO_NOTHING,
|
||||||
|
verbose_name=_('Category'),
|
||||||
|
help_text=_('Part category')
|
||||||
|
)
|
||||||
|
|
||||||
IPN = models.CharField(max_length=100, blank=True, null=True, help_text=_('Internal Part Number'), validators=[validators.validate_part_ipn])
|
IPN = models.CharField(
|
||||||
|
max_length=100, blank=True, null=True,
|
||||||
|
verbose_name=_('IPN'),
|
||||||
|
help_text=_('Internal Part Number'),
|
||||||
|
validators=[validators.validate_part_ipn]
|
||||||
|
)
|
||||||
|
|
||||||
revision = models.CharField(max_length=100, blank=True, null=True, help_text=_('Part revision or version number'))
|
revision = models.CharField(
|
||||||
|
max_length=100, blank=True, null=True,
|
||||||
|
help_text=_('Part revision or version number'),
|
||||||
|
verbose_name=_('Revision'),
|
||||||
|
)
|
||||||
|
|
||||||
link = InvenTreeURLField(blank=True, null=True, help_text=_('Link to external URL'))
|
link = InvenTreeURLField(
|
||||||
|
blank=True, null=True,
|
||||||
|
verbose_name=_('Link'),
|
||||||
|
help_text=_('Link to external URL')
|
||||||
|
)
|
||||||
|
|
||||||
image = StdImageField(
|
image = StdImageField(
|
||||||
upload_to=rename_part_image,
|
upload_to=rename_part_image,
|
||||||
@ -679,10 +712,13 @@ class Part(MPTTModel):
|
|||||||
delete_orphans=True,
|
delete_orphans=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
default_location = TreeForeignKey('stock.StockLocation', on_delete=models.SET_NULL,
|
default_location = TreeForeignKey('stock.StockLocation',
|
||||||
blank=True, null=True,
|
on_delete=models.SET_NULL,
|
||||||
help_text=_('Where is this item normally stored?'),
|
blank=True, null=True,
|
||||||
related_name='default_parts')
|
help_text=_('Where is this item normally stored?'),
|
||||||
|
related_name='default_parts',
|
||||||
|
verbose_name=_('Default Location'),
|
||||||
|
)
|
||||||
|
|
||||||
def get_default_location(self):
|
def get_default_location(self):
|
||||||
""" Get the default location for a Part (may be None).
|
""" Get the default location for a Part (may be None).
|
||||||
@ -733,7 +769,7 @@ class Part(MPTTModel):
|
|||||||
units = models.CharField(max_length=20, default="", blank=True, null=True, help_text=_('Stock keeping units for this part'))
|
units = models.CharField(max_length=20, default="", blank=True, null=True, help_text=_('Stock keeping units for this part'))
|
||||||
|
|
||||||
assembly = models.BooleanField(
|
assembly = models.BooleanField(
|
||||||
default=False,
|
default=part_settings.part_assembly_default,
|
||||||
verbose_name=_('Assembly'),
|
verbose_name=_('Assembly'),
|
||||||
help_text=_('Can this part be built from other parts?')
|
help_text=_('Can this part be built from other parts?')
|
||||||
)
|
)
|
||||||
|
@ -8,6 +8,22 @@ from __future__ import unicode_literals
|
|||||||
from common.models import InvenTreeSetting
|
from common.models import InvenTreeSetting
|
||||||
|
|
||||||
|
|
||||||
|
def part_assembly_default():
|
||||||
|
"""
|
||||||
|
Returns the default value for the 'assembly' field of a Part object
|
||||||
|
"""
|
||||||
|
|
||||||
|
return InvenTreeSetting.get_setting('PART_ASSEMBLY')
|
||||||
|
|
||||||
|
|
||||||
|
def part_template_default():
|
||||||
|
"""
|
||||||
|
Returns the default value for the 'is_template' field of a Part object
|
||||||
|
"""
|
||||||
|
|
||||||
|
return InvenTreeSetting.get_setting('PART_TEMPLATE')
|
||||||
|
|
||||||
|
|
||||||
def part_component_default():
|
def part_component_default():
|
||||||
"""
|
"""
|
||||||
Returns the default value for the 'component' field of a Part object
|
Returns the default value for the 'component' field of a Part object
|
||||||
|
@ -235,6 +235,8 @@ class PartSettingsTest(TestCase):
|
|||||||
InvenTreeSetting.set_setting('PART_PURCHASEABLE', val, self.user)
|
InvenTreeSetting.set_setting('PART_PURCHASEABLE', val, self.user)
|
||||||
InvenTreeSetting.set_setting('PART_SALABLE', val, self.user)
|
InvenTreeSetting.set_setting('PART_SALABLE', val, self.user)
|
||||||
InvenTreeSetting.set_setting('PART_TRACKABLE', val, self.user)
|
InvenTreeSetting.set_setting('PART_TRACKABLE', val, self.user)
|
||||||
|
InvenTreeSetting.set_setting('PART_ASSEMBLY', val, self.user)
|
||||||
|
InvenTreeSetting.set_setting('PART_TEMPLATE', val, self.user)
|
||||||
|
|
||||||
self.assertEqual(val, InvenTreeSetting.get_setting('PART_COMPONENT'))
|
self.assertEqual(val, InvenTreeSetting.get_setting('PART_COMPONENT'))
|
||||||
self.assertEqual(val, InvenTreeSetting.get_setting('PART_PURCHASEABLE'))
|
self.assertEqual(val, InvenTreeSetting.get_setting('PART_PURCHASEABLE'))
|
||||||
@ -247,6 +249,8 @@ class PartSettingsTest(TestCase):
|
|||||||
self.assertEqual(part.purchaseable, val)
|
self.assertEqual(part.purchaseable, val)
|
||||||
self.assertEqual(part.salable, val)
|
self.assertEqual(part.salable, val)
|
||||||
self.assertEqual(part.trackable, val)
|
self.assertEqual(part.trackable, val)
|
||||||
|
self.assertEqual(part.assembly, val)
|
||||||
|
self.assertEqual(part.is_template, val)
|
||||||
|
|
||||||
Part.objects.filter(pk=part.pk).delete()
|
Part.objects.filter(pk=part.pk).delete()
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user