2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-06-18 21:15:41 +00:00

Finally got migrations working together

This commit is contained in:
Oliver
2018-04-22 21:54:12 +10:00
parent cef3c664f9
commit 4bedf0ed4c
86 changed files with 356 additions and 2279 deletions

View File

@ -2,6 +2,7 @@ from django.contrib import admin
from import_export.admin import ImportExportModelAdmin
from .models import PartCategory, Part
from .models import SupplierPart
from .models import BomItem
from .models import PartAttachment
@ -20,8 +21,11 @@ class BomItemAdmin(ImportExportModelAdmin):
list_display = ('part', 'sub_part', 'quantity')
class PartAttachmentAdmin(admin.ModelAdmin):
list_display = ('part', 'attachment')
#class PartAttachmentAdmin(admin.ModelAdmin):
# list_display = ('part', 'attachment')
class SupplierPartAdmin(ImportExportModelAdmin):
list_display = ('part', 'supplier', 'SKU')
"""
@ -36,8 +40,4 @@ class ParameterAdmin(admin.ModelAdmin):
admin.site.register(Part, PartAdmin)
admin.site.register(PartCategory, PartCategoryAdmin)
admin.site.register(BomItem, BomItemAdmin)
admin.site.register(PartAttachment, PartAttachmentAdmin)
# admin.site.register(PartParameter, ParameterAdmin)
# admin.site.register(PartParameterTemplate, ParameterTemplateAdmin)
# admin.site.register(CategoryParameterLink)
admin.site.register(SupplierPart, SupplierPartAdmin)

View File

@ -3,6 +3,7 @@ from crispy_forms.helper import FormHelper
from crispy_forms.layout import Submit
from .models import Part, PartCategory, BomItem
from .models import SupplierPart
class EditPartForm(forms.ModelForm):
@ -73,3 +74,27 @@ class EditBomItemForm(forms.ModelForm):
'sub_part',
'quantity'
]
class EditSupplierPartForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(EditSupplierPartForm, self).__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.form_id = 'id-edit-part-form'
self.helper.form_class = 'blueForms'
self.helper.form_method = 'post'
self.helper.add_input(Submit('submit', 'Submit'))
class Meta:
model = SupplierPart
fields = [
'supplier',
'SKU',
'part',
'description',
'URL',
'manufacturer',
'MPN',
]

View File

@ -1,10 +1,11 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11 on 2018-04-12 05:02
# Generated by Django 1.11.12 on 2018-04-22 11:53
from __future__ import unicode_literals
import django.core.validators
from django.db import migrations, models
import django.db.models.deletion
import part.models
class Migration(migrations.Migration):
@ -12,42 +13,57 @@ class Migration(migrations.Migration):
initial = True
dependencies = [
('company', '0001_initial'),
]
operations = [
migrations.CreateModel(
name='CategoryParameterLink',
name='BomItem',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('quantity', models.PositiveIntegerField(default=1, validators=[django.core.validators.MinValueValidator(0)])),
],
options={
'verbose_name': 'Category Parameter',
'verbose_name_plural': 'Category Parameters',
'verbose_name': 'BOM Item',
},
),
migrations.CreateModel(
name='Part',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=100)),
('description', models.CharField(blank=True, max_length=250)),
('IPN', models.CharField(blank=True, max_length=100)),
('minimum_stock', models.PositiveIntegerField(default=0, validators=[django.core.validators.MinValueValidator(0)])),
('name', models.CharField(help_text='Part name (must be unique)', max_length=100, unique=True)),
('description', models.CharField(help_text='Part description', max_length=250)),
('IPN', models.CharField(blank=True, help_text='Internal Part Number', max_length=100)),
('URL', models.URLField(blank=True, help_text='Link to extenal URL')),
('image', models.ImageField(blank=True, max_length=255, null=True, upload_to=part.models.rename_part_image)),
('minimum_stock', models.PositiveIntegerField(default=0, help_text='Minimum allowed stock level', validators=[django.core.validators.MinValueValidator(0)])),
('units', models.CharField(blank=True, default='pcs', max_length=20)),
('trackable', models.BooleanField(default=False)),
('buildable', models.BooleanField(default=False, help_text='Can this part be built from other parts?')),
('trackable', models.BooleanField(default=False, help_text='Does this part have tracking for unique items?')),
('purchaseable', models.BooleanField(default=True, help_text='Can this part be purchased from external suppliers?')),
('salable', models.BooleanField(default=False, help_text='Can this part be sold to customers?')),
('notes', models.TextField(blank=True)),
],
options={
'verbose_name': 'Part',
'verbose_name_plural': 'Parts',
},
),
migrations.CreateModel(
name='PartAttachment',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('attachment', models.FileField(blank=True, null=True, upload_to=part.models.attach_file)),
('part', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='attachments', to='part.Part')),
],
),
migrations.CreateModel(
name='PartCategory',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=100)),
('description', models.CharField(blank=True, max_length=250)),
('parent', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='children', to='part.PartCategory')),
('name', models.CharField(max_length=100, unique=True)),
('description', models.CharField(max_length=250)),
('parent', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='children', to='part.PartCategory')),
],
options={
'verbose_name': 'Part Category',
@ -55,62 +71,63 @@ class Migration(migrations.Migration):
},
),
migrations.CreateModel(
name='PartParameter',
name='SupplierPart',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('value', models.CharField(blank=True, max_length=50)),
('min_value', models.CharField(blank=True, max_length=50)),
('max_value', models.CharField(blank=True, max_length=50)),
('part', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='parameters', to='part.Part')),
('SKU', models.CharField(help_text='Supplier stock keeping unit', max_length=100)),
('manufacturer', models.CharField(blank=True, help_text='Manufacturer', max_length=100)),
('MPN', models.CharField(blank=True, help_text='Manufacturer part number', max_length=100)),
('URL', models.URLField(blank=True)),
('description', models.CharField(blank=True, max_length=250)),
('single_price', models.DecimalField(decimal_places=3, default=0, max_digits=10)),
('base_cost', models.DecimalField(decimal_places=3, default=0, max_digits=10)),
('packaging', models.CharField(blank=True, max_length=50)),
('multiple', models.PositiveIntegerField(default=1, validators=[django.core.validators.MinValueValidator(0)])),
('minimum', models.PositiveIntegerField(default=1, validators=[django.core.validators.MinValueValidator(0)])),
('lead_time', models.DurationField(blank=True, null=True)),
('part', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='supplier_parts', to='part.Part')),
('supplier', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='parts', to='company.Company')),
],
options={
'verbose_name': 'Part Parameter',
'verbose_name_plural': 'Part Parameters',
},
),
migrations.CreateModel(
name='PartParameterTemplate',
name='SupplierPriceBreak',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=20, unique=True)),
('units', models.CharField(blank=True, max_length=10)),
('format', models.PositiveIntegerField(choices=[(10, 'Numeric'), (20, 'Text'), (30, 'Bool')], default=10, validators=[django.core.validators.MinValueValidator(0)])),
('quantity', models.PositiveIntegerField(validators=[django.core.validators.MinValueValidator(0)])),
('cost', models.DecimalField(decimal_places=3, max_digits=10)),
('part', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='price_breaks', to='part.SupplierPart')),
],
options={
'verbose_name': 'Parameter Template',
'verbose_name_plural': 'Parameter Templates',
},
),
migrations.AddField(
model_name='partparameter',
name='template',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='part.PartParameterTemplate'),
),
migrations.AddField(
model_name='part',
name='category',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='part.PartCategory'),
field=models.ForeignKey(blank=True, help_text='Part category', null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='parts', to='part.PartCategory'),
),
migrations.AddField(
model_name='categoryparameterlink',
name='category',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='part.PartCategory'),
model_name='part',
name='default_supplier',
field=models.ForeignKey(blank=True, help_text='Default supplier part', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='default_parts', to='part.SupplierPart'),
),
migrations.AddField(
model_name='categoryparameterlink',
name='template',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='part.PartParameterTemplate'),
),
migrations.AlterUniqueTogether(
name='partparameter',
unique_together=set([('part', 'template')]),
),
migrations.AlterUniqueTogether(
model_name='bomitem',
name='part',
unique_together=set([('name', 'category'), ('IPN', 'category')]),
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='bom_items', to='part.Part'),
),
migrations.AddField(
model_name='bomitem',
name='sub_part',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='used_in', to='part.Part'),
),
migrations.AlterUniqueTogether(
name='categoryparameterlink',
unique_together=set([('category', 'template')]),
name='supplierpricebreak',
unique_together=set([('part', 'quantity')]),
),
migrations.AlterUniqueTogether(
name='supplierpart',
unique_together=set([('part', 'supplier', 'SKU')]),
),
migrations.AlterUniqueTogether(
name='bomitem',
unique_together=set([('part', 'sub_part')]),
),
]

View File

@ -1,48 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11 on 2018-04-12 06:00
from __future__ import unicode_literals
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('part', '0001_initial'),
]
operations = [
migrations.AlterUniqueTogether(
name='categoryparameterlink',
unique_together=set([]),
),
migrations.RemoveField(
model_name='categoryparameterlink',
name='category',
),
migrations.RemoveField(
model_name='categoryparameterlink',
name='template',
),
migrations.AlterUniqueTogether(
name='partparameter',
unique_together=set([]),
),
migrations.RemoveField(
model_name='partparameter',
name='part',
),
migrations.RemoveField(
model_name='partparameter',
name='template',
),
migrations.DeleteModel(
name='CategoryParameterLink',
),
migrations.DeleteModel(
name='PartParameter',
),
migrations.DeleteModel(
name='PartParameterTemplate',
),
]

View File

@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.12 on 2018-04-17 08:12
# Generated by Django 1.11.12 on 2018-04-22 11:53
from __future__ import unicode_literals
from django.db import migrations, models
@ -9,14 +9,14 @@ import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('stock', '0010_stockitem_build'),
('part', '0020_part_salable'),
('stock', '0001_initial'),
('part', '0001_initial'),
]
operations = [
migrations.AddField(
model_name='part',
name='default_location',
field=models.ForeignKey(blank=True, help_text='Where is this item normally stored?', null=True, on_delete=django.db.models.deletion.SET_NULL, to='stock.StockLocation'),
field=models.ForeignKey(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'),
),
]

View File

@ -1,19 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11 on 2018-04-12 06:44
from __future__ import unicode_literals
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('part', '0002_auto_20180412_0600'),
]
operations = [
migrations.AlterUniqueTogether(
name='part',
unique_together=set([('name', 'category')]),
),
]

View File

@ -1,21 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11 on 2018-04-13 08:34
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('part', '0003_auto_20180412_0644'),
]
operations = [
migrations.AlterField(
model_name='part',
name='category',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='parts', to='part.PartCategory'),
),
]

View File

@ -1,20 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11 on 2018-04-13 12:30
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('part', '0004_auto_20180413_0834'),
]
operations = [
migrations.AlterField(
model_name='partcategory',
name='name',
field=models.CharField(max_length=100, unique=True),
),
]

View File

@ -1,21 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11 on 2018-04-14 04:03
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('part', '0005_auto_20180413_1230'),
]
operations = [
migrations.AlterField(
model_name='part',
name='category',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='parts', to='part.PartCategory'),
),
]

View File

@ -1,33 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11 on 2018-04-14 04:16
from __future__ import unicode_literals
import django.core.validators
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('part', '0006_auto_20180414_0403'),
]
operations = [
migrations.CreateModel(
name='BomItem',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('quantity', models.PositiveIntegerField(default=1, validators=[django.core.validators.MinValueValidator(0)])),
('part', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='bom_items', to='part.Part')),
('sub_part', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='used_in', to='part.Part')),
],
options={
'verbose_name': 'BOM Item',
},
),
migrations.AlterUniqueTogether(
name='bomitem',
unique_together=set([('part', 'sub_part')]),
),
]

View File

@ -1,20 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11 on 2018-04-14 06:31
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('part', '0007_auto_20180414_0416'),
]
operations = [
migrations.AddField(
model_name='part',
name='URL',
field=models.URLField(blank=True),
),
]

View File

@ -1,20 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11 on 2018-04-14 06:53
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('part', '0008_part_url'),
]
operations = [
migrations.AddField(
model_name='part',
name='image',
field=models.ImageField(blank=True, upload_to='part_images'),
),
]

View File

@ -1,21 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11 on 2018-04-14 07:25
from __future__ import unicode_literals
from django.db import migrations, models
import part.models
class Migration(migrations.Migration):
dependencies = [
('part', '0009_part_image'),
]
operations = [
migrations.AlterField(
model_name='part',
name='image',
field=models.ImageField(blank=True, max_length=255, null=True, upload_to=part.models.rename_part_image),
),
]

View File

@ -1,25 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11 on 2018-04-14 08:21
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
import part.models
class Migration(migrations.Migration):
dependencies = [
('part', '0010_auto_20180414_0725'),
]
operations = [
migrations.CreateModel(
name='PartAttachment',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('attachment', models.FileField(blank=True, null=True, upload_to=part.models.attach_file)),
('part', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='attachments', to='part.Part')),
],
),
]

View File

@ -1,21 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11 on 2018-04-14 10:32
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('part', '0011_partattachment'),
]
operations = [
migrations.AlterField(
model_name='part',
name='category',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='parts', to='part.PartCategory'),
),
]

View File

@ -1,24 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11 on 2018-04-14 22:38
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('part', '0012_auto_20180414_1032'),
]
operations = [
migrations.AlterField(
model_name='part',
name='name',
field=models.CharField(max_length=100, unique=True),
),
migrations.AlterUniqueTogether(
name='part',
unique_together=set([]),
),
]

View File

@ -1,21 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11 on 2018-04-15 01:07
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('part', '0013_auto_20180414_2238'),
]
operations = [
migrations.AlterField(
model_name='partcategory',
name='parent',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='children', to='part.PartCategory'),
),
]

View File

@ -1,20 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11 on 2018-04-15 03:02
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('part', '0014_auto_20180415_0107'),
]
operations = [
migrations.AlterField(
model_name='partcategory',
name='description',
field=models.CharField(max_length=250),
),
]

View File

@ -1,20 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11 on 2018-04-15 03:16
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('part', '0015_auto_20180415_0302'),
]
operations = [
migrations.AlterField(
model_name='part',
name='description',
field=models.CharField(max_length=250),
),
]

View File

@ -1,20 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11 on 2018-04-15 14:21
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('part', '0016_auto_20180415_0316'),
]
operations = [
migrations.AddField(
model_name='part',
name='purchaseable',
field=models.BooleanField(default=True),
),
]

View File

@ -1,20 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11 on 2018-04-16 12:08
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('part', '0017_part_purchaseable'),
]
operations = [
migrations.AddField(
model_name='part',
name='buildable',
field=models.BooleanField(default=False),
),
]

View File

@ -1,62 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11 on 2018-04-16 12:49
from __future__ import unicode_literals
import django.core.validators
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('part', '0018_part_buildable'),
]
operations = [
migrations.AlterField(
model_name='part',
name='IPN',
field=models.CharField(blank=True, help_text='Internal Part Number', max_length=100),
),
migrations.AlterField(
model_name='part',
name='URL',
field=models.URLField(blank=True, help_text='Link to extenal URL'),
),
migrations.AlterField(
model_name='part',
name='buildable',
field=models.BooleanField(default=False, help_text='Can this part be built from other parts?'),
),
migrations.AlterField(
model_name='part',
name='category',
field=models.ForeignKey(blank=True, help_text='Part category', null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='parts', to='part.PartCategory'),
),
migrations.AlterField(
model_name='part',
name='description',
field=models.CharField(help_text='Part description', max_length=250),
),
migrations.AlterField(
model_name='part',
name='minimum_stock',
field=models.PositiveIntegerField(default=0, help_text='Minimum allowed stock level', validators=[django.core.validators.MinValueValidator(0)]),
),
migrations.AlterField(
model_name='part',
name='name',
field=models.CharField(help_text='Part name (must be unique)', max_length=100, unique=True),
),
migrations.AlterField(
model_name='part',
name='purchaseable',
field=models.BooleanField(default=True, help_text='Can this part be purchased from external suppliers?'),
),
migrations.AlterField(
model_name='part',
name='trackable',
field=models.BooleanField(default=False, help_text='Does this part have tracking for unique items?'),
),
]

View File

@ -1,20 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.12 on 2018-04-17 08:06
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('part', '0019_auto_20180416_1249'),
]
operations = [
migrations.AddField(
model_name='part',
name='salable',
field=models.BooleanField(default=False, help_text='Can this part be sold to customers?'),
),
]

View File

@ -1,27 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.12 on 2018-04-17 08:19
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('company', '0007_auto_20180416_1253'),
('part', '0021_part_default_location'),
]
operations = [
migrations.AddField(
model_name='part',
name='default_supplier',
field=models.ForeignKey(blank=True, help_text='Default supplier part', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='default_parts', to='company.SupplierPart'),
),
migrations.AlterField(
model_name='part',
name='default_location',
field=models.ForeignKey(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'),
),
]

View File

@ -1,20 +0,0 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.11.12 on 2018-04-17 15:34
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('part', '0022_auto_20180417_0819'),
]
operations = [
migrations.AddField(
model_name='part',
name='notes',
field=models.TextField(blank=True),
),
]

View File

@ -11,7 +11,7 @@ from django.db.models.signals import pre_delete
from django.dispatch import receiver
from InvenTree.models import InvenTreeTree
from company.models import Company
class PartCategory(InvenTreeTree):
""" PartCategory provides hierarchical organization of Part objects.
@ -111,7 +111,7 @@ class Part(models.Model):
related_name='default_parts')
# Default supplier part
default_supplier = models.ForeignKey('company.SupplierPart',
default_supplier = models.ForeignKey('part.SupplierPart',
on_delete=models.SET_NULL,
blank=True, null=True,
help_text='Default supplier part',
@ -352,3 +352,78 @@ class BomItem(models.Model):
par=self.part.name,
child=self.sub_part.name,
n=self.quantity)
class SupplierPart(models.Model):
""" Represents a unique part as provided by a Supplier
Each SupplierPart is identified by a MPN (Manufacturer Part Number)
Each SupplierPart is also linked to a Part object
- A Part may be available from multiple suppliers
"""
def get_absolute_url(self):
return "/supplier-part/{id}/".format(id=self.id)
class Meta:
unique_together = ('part', 'supplier', 'SKU')
# Link to an actual part
# The part will have a field 'supplier_parts' which links to the supplier part options
part = models.ForeignKey(Part, on_delete=models.CASCADE,
related_name='supplier_parts')
supplier = models.ForeignKey(Company, on_delete=models.CASCADE,
related_name='parts')
SKU = models.CharField(max_length=100, help_text='Supplier stock keeping unit')
manufacturer = models.CharField(max_length=100, blank=True, help_text='Manufacturer')
MPN = models.CharField(max_length=100, blank=True, help_text='Manufacturer part number')
URL = models.URLField(blank=True)
description = models.CharField(max_length=250, blank=True)
# Default price for a single unit
single_price = models.DecimalField(max_digits=10, decimal_places=3, default=0)
# Base charge added to order independent of quantity e.g. "Reeling Fee"
base_cost = models.DecimalField(max_digits=10, decimal_places=3, default=0)
# packaging that the part is supplied in, e.g. "Reel"
packaging = models.CharField(max_length=50, blank=True)
# multiple that the part is provided in
multiple = models.PositiveIntegerField(default=1, validators=[MinValueValidator(0)])
# Mimumum number required to order
minimum = models.PositiveIntegerField(default=1, validators=[MinValueValidator(0)])
# lead time for parts that cannot be delivered immediately
lead_time = models.DurationField(blank=True, null=True)
def __str__(self):
return "{sku} - {supplier}".format(
sku=self.SKU,
supplier=self.supplier.name)
class SupplierPriceBreak(models.Model):
""" Represents a quantity price break for a SupplierPart
- Suppliers can offer discounts at larger quantities
- SupplierPart(s) may have zero-or-more associated SupplierPriceBreak(s)
"""
part = models.ForeignKey(SupplierPart, on_delete=models.CASCADE, related_name='price_breaks')
quantity = models.PositiveIntegerField(validators=[MinValueValidator(0)])
cost = models.DecimalField(max_digits=10, decimal_places=3)
class Meta:
unique_together = ("part", "quantity")
def __str__(self):
return "{mpn} - {cost}{currency} @ {quan}".format(
mpn=self.part.MPN,
cost=self.cost,
currency=self.currency if self.currency else '',
quan=self.quantity)

View File

@ -4,6 +4,19 @@ from django.views.generic.base import RedirectView
from . import views
from . import api
supplier_part_detail_urls = [
url(r'edit/?', views.SupplierPartEdit.as_view(), name='supplier-part-edit'),
url(r'delete/?', views.SupplierPartDelete.as_view(), name='supplier-part-delete'),
url('^.*$', views.SupplierPartDetail.as_view(), name='supplier-part-detail'),
]
supplier_part_urls = [
url(r'^new/?', views.SupplierPartCreate.as_view(), name='supplier-part-create'),
url(r'^(?P<pk>\d+)/', include(supplier_part_detail_urls)),
]
# URL list for part category API
part_cat_api_urls = [

View File

@ -7,8 +7,14 @@ from django.http import HttpResponseRedirect
from django.views.generic import DetailView, ListView
from django.views.generic.edit import UpdateView, DeleteView, CreateView
from .forms import EditPartForm, EditCategoryForm, EditBomItemForm
from .models import PartCategory, Part, BomItem
from .models import SupplierPart
from .forms import EditPartForm
from .forms import EditCategoryForm
from .forms import EditBomItemForm
from .forms import EditSupplierPartForm
class PartIndex(ListView):
@ -191,3 +197,53 @@ class BomItemDelete(DeleteView):
return super(BomItemDelete, self).post(request, *args, **kwargs)
else:
return HttpResponseRedirect(self.get_object().get_absolute_url())
class SupplierPartDetail(DetailView):
model = SupplierPart
template_name = 'company/partdetail.html'
context_object_name = 'part'
queryset = SupplierPart.objects.all()
class SupplierPartEdit(UpdateView):
model = SupplierPart
template_name = 'company/partedit.html'
context_object_name = 'part'
form_class = EditSupplierPartForm
class SupplierPartCreate(CreateView):
model = SupplierPart
form_class = EditSupplierPartForm
template_name = 'company/partcreate.html'
context_object_name = 'part'
def get_initial(self):
initials = super(SupplierPartCreate, self).get_initial().copy()
supplier_id = self.request.GET.get('supplier', None)
part_id = self.request.GET.get('part', None)
if supplier_id:
initials['supplier'] = get_object_or_404(Supplier, pk=supplier_id)
# TODO
# self.fields['supplier'].disabled = True
if part_id:
initials['part'] = get_object_or_404(Part, pk=part_id)
# TODO
# self.fields['part'].disabled = True
return initials
class SupplierPartDelete(DeleteView):
model = SupplierPart
success_url = '/supplier/'
template_name = 'company/partdelete.html'
def post(self, request, *args, **kwargs):
if 'confirm' in request.POST:
return super(SupplierPartDelete, self).post(request, *args, **kwargs)
else:
return HttpResponseRedirect(self.get_object().get_absolute_url())