2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-04-29 20:16:44 +00:00
This commit is contained in:
Oliver Walters 2017-03-29 23:19:53 +11:00
parent b2eca2aa48
commit 8ba4ea344e
5 changed files with 77 additions and 60 deletions

View File

@ -1,5 +1,5 @@
from __future__ import unicode_literals from __future__ import unicode_literals
from django.utils.translation import ugettext as _
from django.db import models from django.db import models
from django.db.models import Sum from django.db.models import Sum
from django.core.exceptions import ObjectDoesNotExist, ValidationError from django.core.exceptions import ObjectDoesNotExist, ValidationError
@ -10,15 +10,15 @@ from InvenTree.models import InvenTreeTree
class PartCategory(InvenTreeTree): class PartCategory(InvenTreeTree):
""" PartCategory provides hierarchical organization of Part objects. """ PartCategory provides hierarchical organization of Part objects.
""" """
class Meta: class Meta:
verbose_name = "Part Category" verbose_name = "Part Category"
verbose_name_plural = "Part Categories" verbose_name_plural = "Part Categories"
class Part(models.Model): class Part(models.Model):
""" Represents a """ """ Represents a """
name = models.CharField(max_length=100) name = models.CharField(max_length=100)
description = models.CharField(max_length=250, blank=True) description = models.CharField(max_length=250, blank=True)
IPN = models.CharField(max_length=100, blank=True) IPN = models.CharField(max_length=100, blank=True)
@ -26,7 +26,7 @@ class Part(models.Model):
minimum_stock = models.IntegerField(default=0) minimum_stock = models.IntegerField(default=0)
units = models.CharField(max_length=20, default="pcs", blank=True) units = models.CharField(max_length=20, default="pcs", blank=True)
trackable = models.BooleanField(default=False) trackable = models.BooleanField(default=False)
def __str__(self): def __str__(self):
if self.IPN: if self.IPN:
return "{name} ({ipn})".format( return "{name} ({ipn})".format(
@ -34,39 +34,39 @@ class Part(models.Model):
name=self.name) name=self.name)
else: else:
return self.name return self.name
class Meta: class Meta:
verbose_name = "Part" verbose_name = "Part"
verbose_name_plural = "Parts" verbose_name_plural = "Parts"
@property @property
def stock(self): def stock(self):
""" Return the total stock quantity for this part. """ Return the total stock quantity for this part.
Part may be stored in multiple locations Part may be stored in multiple locations
""" """
stocks = self.locations.all() stocks = self.locations.all()
if len(stocks) == 0: if len(stocks) == 0:
return 0 return 0
result = stocks.aggregate(total=Sum('quantity')) result = stocks.aggregate(total=Sum('quantity'))
return result['total'] return result['total']
@property @property
def projects(self): def projects(self):
""" Return a list of unique projects that this part is associated with """ Return a list of unique projects that this part is associated with
""" """
project_ids = set() project_ids = set()
project_parts = self.projectpart_set.all() project_parts = self.projectpart_set.all()
projects = [] projects = []
for pp in project_parts: for pp in project_parts:
if pp.project.id not in project_ids: if pp.project.id not in project_ids:
project_ids.add(pp.project.id) project_ids.add(pp.project.id)
projects.append(pp.project) projects.append(pp.project)
return projects return projects
@ -78,28 +78,31 @@ class PartParameterTemplate(models.Model):
name = models.CharField(max_length=20) name = models.CharField(max_length=20)
description = models.CharField(max_length=100, blank=True) description = models.CharField(max_length=100, blank=True)
units = models.CharField(max_length=10, blank=True) units = models.CharField(max_length=10, blank=True)
default_value = models.CharField(max_length=50, blank=True) default_value = models.CharField(max_length=50, blank=True)
default_min = models.CharField(max_length=50, blank=True) default_min = models.CharField(max_length=50, blank=True)
default_max = models.CharField(max_length=50, blank=True) default_max = models.CharField(max_length=50, blank=True)
# Parameter format # Parameter format
PARAM_NUMERIC = 10 PARAM_NUMERIC = 10
PARAM_TEXT = 20 PARAM_TEXT = 20
PARAM_BOOL = 30 PARAM_BOOL = 30
PARAM_TYPE_CODES = {
PARAM_NUMERIC: _("Numeric"),
PARAM_TEXT: _("Text"),
PARAM_BOOL: _("Bool")
}
format = models.IntegerField( format = models.IntegerField(
default=PARAM_NUMERIC, default=PARAM_NUMERIC,
choices=[ choices=PARAM_TYPE_CODES.items())
(PARAM_NUMERIC, "Numeric"),
(PARAM_TEXT, "Text"),
(PARAM_BOOL, "Boolean")])
def __str__(self): def __str__(self):
return "{name} ({units})".format( return "{name} ({units})".format(
name=self.name, name=self.name,
units=self.units) units=self.units)
class Meta: class Meta:
verbose_name = "Parameter Template" verbose_name = "Parameter Template"
verbose_name_plural = "Parameter Templates" verbose_name_plural = "Parameter Templates"
@ -110,7 +113,7 @@ class CategoryParameterLink(models.Model):
""" """
category = models.ForeignKey(PartCategory, on_delete=models.CASCADE) category = models.ForeignKey(PartCategory, on_delete=models.CASCADE)
template = models.ForeignKey(PartParameterTemplate, on_delete=models.CASCADE) template = models.ForeignKey(PartParameterTemplate, on_delete=models.CASCADE)
def __str__(self): def __str__(self):
return "{name} - {cat}".format( return "{name} - {cat}".format(
name=self.template.name, name=self.template.name,
@ -119,20 +122,20 @@ class CategoryParameterLink(models.Model):
class Meta: class Meta:
verbose_name = "Category Parameter" verbose_name = "Category Parameter"
verbose_name_plural = "Category Parameters" verbose_name_plural = "Category Parameters"
class PartParameter(models.Model): class PartParameter(models.Model):
""" PartParameter is associated with a single part """ PartParameter is associated with a single part
""" """
part = models.ForeignKey(Part, on_delete=models.CASCADE, related_name='parameters') part = models.ForeignKey(Part, on_delete=models.CASCADE, related_name='parameters')
template = models.ForeignKey(PartParameterTemplate) template = models.ForeignKey(PartParameterTemplate)
# Value data # Value data
value = models.CharField(max_length=50, blank=True) value = models.CharField(max_length=50, blank=True)
min_value = models.CharField(max_length=50, blank=True) min_value = models.CharField(max_length=50, blank=True)
max_value = models.CharField(max_length=50, blank=True) max_value = models.CharField(max_length=50, blank=True)
# Prevent multiple parameters of the same template # Prevent multiple parameters of the same template
# from being added to the same part # from being added to the same part
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
@ -141,27 +144,27 @@ class PartParameter(models.Model):
return return
if len(params) == 1 and params[0].id != self.id: if len(params) == 1 and params[0].id != self.id:
return return
super(PartParameter, self).save(*args, **kwargs) super(PartParameter, self).save(*args, **kwargs)
def __str__(self): def __str__(self):
return "{name} : {val}{units}".format( return "{name} : {val}{units}".format(
name=self.template.name, name=self.template.name,
val=self.value, val=self.value,
units=self.template.units) units=self.template.units)
@property @property
def units(self): def units(self):
return self.template.units return self.template.units
@property @property
def name(self): def name(self):
return self.template.name return self.template.name
class Meta: class Meta:
verbose_name = "Part Parameter" verbose_name = "Part Parameter"
verbose_name_plural = "Part Parameters" verbose_name_plural = "Part Parameters"
class PartRevision(models.Model): class PartRevision(models.Model):
""" A PartRevision represents a change-notification to a Part """ A PartRevision represents a change-notification to a Part
@ -169,12 +172,12 @@ class PartRevision(models.Model):
which should be tracked. which should be tracked.
UniqueParts can have a single associated PartRevision UniqueParts can have a single associated PartRevision
""" """
part = models.ForeignKey(Part, on_delete=models.CASCADE) part = models.ForeignKey(Part, on_delete=models.CASCADE)
name = models.CharField(max_length=100) name = models.CharField(max_length=100)
description = models.CharField(max_length=500) description = models.CharField(max_length=500)
revision_date = models.DateField(auto_now_add=True) revision_date = models.DateField(auto_now_add=True)
def __str__(self): def __str__(self):
return self.name return self.name

View File

@ -1,6 +1,6 @@
from django.contrib import admin from django.contrib import admin
from .models import ProjectCategory, Project, ProjectPart from .models import ProjectCategory, Project, ProjectPart, ProjectRun
class ProjectCategoryAdmin(admin.ModelAdmin): class ProjectCategoryAdmin(admin.ModelAdmin):
@ -14,6 +14,11 @@ class ProjectAdmin(admin.ModelAdmin):
class ProjectPartAdmin(admin.ModelAdmin): class ProjectPartAdmin(admin.ModelAdmin):
list_display = ('part', 'project', 'quantity') list_display = ('part', 'project', 'quantity')
class ProjectRunAdmin(admin.ModelAdmin):
list_display = ('project', 'quantity', 'run_date')
admin.site.register(ProjectCategory, ProjectCategoryAdmin) admin.site.register(ProjectCategory, ProjectCategoryAdmin)
admin.site.register(Project, ProjectAdmin) admin.site.register(Project, ProjectAdmin)
admin.site.register(ProjectPart, ProjectPartAdmin) admin.site.register(ProjectPart, ProjectPartAdmin)
admin.site.register(ProjectRun, ProjectRunAdmin)

View File

@ -1,4 +1,5 @@
from __future__ import unicode_literals from __future__ import unicode_literals
from django.utils.translation import ugettext as _
from django.db import models from django.db import models
@ -46,16 +47,18 @@ class ProjectPart(models.Model):
OVERAGE_PERCENT = 0 OVERAGE_PERCENT = 0
OVERAGE_ABSOLUTE = 1 OVERAGE_ABSOLUTE = 1
OVARAGE_CODES = {
OVERAGE_PERCENT: _("Percent"),
OVERAGE_ABSOLUTE: _("Absolute")
}
part = models.ForeignKey(Part, on_delete=models.CASCADE) part = models.ForeignKey(Part, on_delete=models.CASCADE)
project = models.ForeignKey(Project, on_delete=models.CASCADE) project = models.ForeignKey(Project, on_delete=models.CASCADE)
quantity = models.PositiveIntegerField(default=1) quantity = models.PositiveIntegerField(default=1)
overage = models.FloatField(default=0) overage = models.FloatField(default=0)
overage_type = models.PositiveIntegerField( overage_type = models.PositiveIntegerField(
default=1, default=1,
choices=[ choices=OVARAGE_CODES.items())
(OVERAGE_PERCENT, "Percent"),
(OVERAGE_ABSOLUTE, "Absolute")
])
def __str__(self): def __str__(self):
return "{quan} x {name}".format( return "{quan} x {name}".format(

View File

@ -1,5 +1,5 @@
from __future__ import unicode_literals from __future__ import unicode_literals
from django.utils.translation import ugettext as _
from django.db import models from django.db import models
from part.models import Part from part.models import Part
@ -19,21 +19,27 @@ class StockItem(models.Model):
updated = models.DateField(auto_now=True) updated = models.DateField(auto_now=True)
# Stock status types # Stock status types
ITEM_IN_PROGRESS = 0 ITEM_IN_STOCK = 10
ITEM_INCOMING = 5 ITEM_INCOMING = 15
ITEM_DAMAGED = 10 ITEM_IN_PROGRESS = 20
ITEM_ATTENTION = 20 ITEM_COMPLETE = 25
ITEM_COMPLETE = 50 ITEM_ATTENTION = 50
ITEM_DAMAGED = 55
ITEM_DESTROYED = 60
ITEM_STATUS_CODES = {
ITEM_IN_STOCK: _("In stock"),
ITEM_INCOMING: _("Incoming"),
ITEM_IN_PROGRESS: _("In progress"),
ITEM_COMPLETE: _("Complete"),
ITEM_ATTENTION: _("Attention needed"),
ITEM_DAMAGED: _("Damaged"),
ITEM_DESTROYED: _("Destroyed")
}
status = models.PositiveIntegerField( status = models.PositiveIntegerField(
default=ITEM_IN_PROGRESS, default=ITEM_IN_STOCK,
choices=[ choices=ITEM_STATUS_CODES.items())
(ITEM_IN_PROGRESS, "In progress"),
(ITEM_INCOMING, "Incoming"),
(ITEM_DAMAGED, "Damaged"),
(ITEM_ATTENTION, "Requires attention"),
(ITEM_COMPLETE, "Complete")
])
# If stock item is incoming, an (optional) ETA field # If stock item is incoming, an (optional) ETA field
expected_arrival = models.DateField(null=True, blank=True) expected_arrival = models.DateField(null=True, blank=True)

View File

@ -32,7 +32,7 @@ class SupplierPart(models.Model):
- A Part may be available from multiple suppliers - A Part may be available from multiple suppliers
""" """
part = models.ForeignKey(Part, part = models.ForeignKey(Part,null=True,blank=True,
on_delete=models.CASCADE) on_delete=models.CASCADE)
supplier = models.ForeignKey(Supplier, supplier = models.ForeignKey(Supplier,
on_delete=models.CASCADE) on_delete=models.CASCADE)
@ -55,8 +55,8 @@ class SupplierPart(models.Model):
lead_time = models.DurationField(blank=True, null=True) lead_time = models.DurationField(blank=True, null=True)
def __str__(self): def __str__(self):
return "{mpn} - {supplier}".format( return "{sku} - {supplier}".format(
mpn=self.MPN, sku=self.SKU,
supplier=self.supplier.name) supplier=self.supplier.name)