Merge pull request #4 from SchrodingersGat/master

Added more models
This commit is contained in:
Oliver 2017-03-28 23:14:25 +11:00 committed by GitHub
commit 2d9206478e
10 changed files with 101 additions and 53 deletions

View File

@ -1,13 +1,10 @@
language: python language: python
python: python:
- 2.7
- 3.3 - 3.3
- 3.4
- 3.5
before_install: before_install:
- pip install pep8 - pip install pep8
script: script:
# TODO - Only perform PEP8 checks on files that have been changed in this push / PR # TODO - Only perform PEP8 checks on files that have been changed in this push / PR
- find . -name \*.py -exec pep8 --ignore=E402 {} + - find . -name \*.py -exec pep8 --ignore=E402,W293 {} +

View File

@ -4,12 +4,37 @@ from django.db import models
from django.core.exceptions import ObjectDoesNotExist from django.core.exceptions import ObjectDoesNotExist
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
class Company(models.Model):
""" Abstract model representing an external company
"""
class Meta:
abstract = True
name = models.CharField(max_length=100)
URL = models.URLField(blank=True)
address = models.CharField(max_length=200,
blank=True)
phone = models.CharField(max_length=50,
blank=True)
email = models.EmailField(blank=True)
contact = models.CharField(max_length=100,
blank=True)
notes = models.CharField(max_length=500,
blank=True)
def __str__(self):
return self.name
class InvenTreeTree(models.Model): class InvenTreeTree(models.Model):
""" Provides an abstracted self-referencing tree model for data categories. """ Provides an abstracted self-referencing tree model for data categories.
- Each Category has one parent Category, which can be blank (for a top-level Category). - Each Category has one parent Category, which can be blank (for a top-level Category).
- Each Category can have zero-or-more child Categor(y/ies) - Each Category can have zero-or-more child Categor(y/ies)
""" """
class Meta:
abstract = True
name = models.CharField(max_length=100) name = models.CharField(max_length=100)
description = models.CharField(max_length=250) description = models.CharField(max_length=250)
parent = models.ForeignKey('self', parent = models.ForeignKey('self',
@ -123,8 +148,4 @@ class InvenTreeTree(models.Model):
This is recursive - Make it not so. This is recursive - Make it not so.
""" """
return self.path return self.path
class Meta:
abstract = True

View File

@ -4,7 +4,7 @@ from .models import PartCategory, Part
class PartAdmin(admin.ModelAdmin): class PartAdmin(admin.ModelAdmin):
list_display = ('name', 'IPN', 'quantity', 'category') list_display = ('name', 'IPN', 'stock', 'category')
# Custom form for PartCategory # Custom form for PartCategory
class PartCategoryAdmin(admin.ModelAdmin): class PartCategoryAdmin(admin.ModelAdmin):

View File

@ -45,7 +45,7 @@ class Part(models.Model):
return self.stockitem_set.all() return self.stockitem_set.all()
@property @property
def quantity(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
""" """

View File

@ -9,7 +9,7 @@ class PartSerializer(serializers.ModelSerializer):
'IPN', 'IPN',
'description', 'description',
'category', 'category',
'quantity') 'stock')
class PartCategorySerializer(serializers.ModelSerializer): class PartCategorySerializer(serializers.ModelSerializer):
class Meta: class Meta:

View File

@ -6,7 +6,7 @@ class WarehouseAdmin(admin.ModelAdmin):
list_display = ('name', 'path', 'description') list_display = ('name', 'path', 'description')
class StockItemAdmin(admin.ModelAdmin): class StockItemAdmin(admin.ModelAdmin):
list_display = ('part', 'quantity', 'location', 'updated') list_display = ('part', 'quantity', 'location', 'status', 'updated')
admin.site.register(Warehouse, WarehouseAdmin) admin.site.register(Warehouse, WarehouseAdmin)
admin.site.register(StockItem, StockItemAdmin) admin.site.register(StockItem, StockItemAdmin)

View File

@ -15,6 +15,20 @@ class StockItem(models.Model):
quantity = models.IntegerField() quantity = models.IntegerField()
updated = models.DateField(auto_now=True) updated = models.DateField(auto_now=True)
# Stock status types
ITEM_IN_PROGRESS = 0
ITEM_DAMAGED = 10
ITEM_ATTENTION = 20
ITEM_COMPLETE = 50
status = models.IntegerField(default=ITEM_IN_PROGRESS,
choices=[
(ITEM_IN_PROGRESS, "In progress"),
(ITEM_DAMAGED, "Damaged"),
(ITEM_ATTENTION, "Requires attention"),
(ITEM_COMPLETE, "Complete")
])
def __str__(self): def __str__(self):
return "{n} x {part} @ {loc}".format( return "{n} x {part} @ {loc}".format(
n = self.quantity, n = self.quantity,

View File

@ -1,9 +1,10 @@
from django.contrib import admin from django.contrib import admin
from .models import Supplier, SupplierPart from .models import Supplier, SupplierPart, Customer
class SupplierAdmin(admin.ModelAdmin): class CompanyAdmin(admin.ModelAdmin):
list_display=('name','URL','contact') list_display=('name','URL','contact')
admin.site.register(Supplier, SupplierAdmin) admin.site.register(Customer, CompanyAdmin)
admin.site.register(Supplier, CompanyAdmin)
admin.site.register(SupplierPart) admin.site.register(SupplierPart)

View File

@ -2,66 +2,60 @@ from __future__ import unicode_literals
from django.db import models from django.db import models
from InvenTree.models import Company
from part.models import Part from part.models import Part
class Supplier(models.Model):
class Supplier(Company):
""" Represents a manufacturer or supplier """ Represents a manufacturer or supplier
""" """
name = models.CharField(max_length=100) pass
URL = models.URLField(blank=True)
address = models.CharField(max_length=200,
blank=True) class Customer(Company):
phone = models.CharField(max_length=50, pass
blank=True)
email = models.EmailField(blank=True)
contact = models.CharField(max_length=100,
blank=True)
notes = models.CharField(max_length=500,
blank=True)
def __str__(self):
return self.name
class SupplierPart(models.Model): class SupplierPart(models.Model):
""" Represents a unique part as provided by a Supplier """ Represents a unique part as provided by a Supplier
Each SupplierPart is identified by a MPN (Manufacturer Part Number) Each SupplierPart is identified by a MPN (Manufacturer Part Number)
Each SupplierPart is also linked to a Part object Each SupplierPart is also linked to a Part object
- A Part may be available from multiple suppliers - A Part may be available from multiple suppliers
""" """
supplier = models.ForeignKey(Supplier, supplier = models.ForeignKey(Supplier,
on_delete=models.CASCADE) on_delete=models.CASCADE)
part = models.ForeignKey(Part, part = models.ForeignKey(Part,
on_delete=models.CASCADE) on_delete=models.CASCADE)
MPN = models.CharField(max_length=100) MPN = models.CharField(max_length=100)
URL = models.URLField(blank=True) URL = models.URLField(blank=True)
description = models.CharField(max_length=250, description = models.CharField(max_length=250,
blank=True) blank=True)
def __str__(self): def __str__(self):
return "{mpn} - {supplier}".format( return "{mpn} - {supplier}".format(
mpn = self.MPN, mpn = self.MPN,
supplier = self.supplier.name) supplier = self.supplier.name)
class SupplierPriceBreak(models.Model): class SupplierPriceBreak(models.Model):
""" Represents a quantity price break for a SupplierPart """ Represents a quantity price break for a SupplierPart
- Suppliers can offer discounts at larger quantities - Suppliers can offer discounts at larger quantities
- SupplierPart(s) may have zero-or-more associated SupplierPriceBreak(s) - SupplierPart(s) may have zero-or-more associated SupplierPriceBreak(s)
""" """
part = models.ForeignKey(SupplierPart, part = models.ForeignKey(SupplierPart,
on_delete=models.CASCADE) on_delete=models.CASCADE)
quantity = models.IntegerField() quantity = models.IntegerField()
cost = models.DecimalField(max_digits=10, decimal_places=3) cost = models.DecimalField(max_digits=10, decimal_places=3)
currency = models.CharField(max_length=10, currency = models.CharField(max_length=10,
blank=True) blank=True)
def __str__(self): def __str__(self):
return "{mpn} - {cost}{currency} @ {quan}".format( return "{mpn} - {cost}{currency} @ {quan}".format(
mpn = part.MPN, mpn=part.MPN,
cost = self.cost, cost=self.cost,
currency = self.currency if self.currency else '', currency=self.currency if self.currency else '',
quan = self.quantity) quan=self.quantity)

View File

@ -3,39 +3,60 @@ from __future__ import unicode_literals
from django.db import models from django.db import models
from django.contrib.auth.models import User from django.contrib.auth.models import User
from supplier.models import Customer
from part.models import Part, PartRevision from part.models import Part, PartRevision
class UniquePart(models.Model): class UniquePart(models.Model):
""" A unique instance of a Part object. """ A unique instance of a Part object.
Used for tracking parts based on serial numbers, Used for tracking parts based on serial numbers,
and tracking all events in the life of a part and tracking all events in the life of a part
""" """
part = models.ForeignKey(Part, on_delete=models.CASCADE) part = models.ForeignKey(Part, on_delete=models.CASCADE)
revision = models.ForeignKey(PartRevision, revision = models.ForeignKey(PartRevision,
on_delete=models.CASCADE, on_delete=models.CASCADE,
blank=True, blank=True,
null=True) null=True)
creation_date = models.DateField(auto_now_add=True, creation_date = models.DateField(auto_now_add=True,
editable=False) editable=False)
serial = models.IntegerField() serial = models.IntegerField()
createdBy = models.ForeignKey(User) createdBy = models.ForeignKey(User)
customer = models.ForeignKey(Customer, blank=True, null=True)
# Part status types
PART_IN_PROGRESS = 0
PART_IN_STOCK = 10
PART_SHIPPED = 20
PART_RETURNED = 30
PART_DAMAGED = 40
PART_DESTROYED = 50
status = models.IntegerField(default=PART_IN_PROGRESS,
choices=[
(PART_IN_PROGRESS, "In progress"),
(PART_IN_STOCK, "In stock"),
(PART_SHIPPED, "Shipped"),
(PART_RETURNED, "Returned"),
(PART_DAMAGED, "Damaged"),
(PART_DESTROYED, "Destroyed"),
])
def __str__(self): def __str__(self):
return self.part.name return self.part.name
class PartTrackingInfo(models.Model): class PartTrackingInfo(models.Model):
""" Single data-point in the life of a UniquePart """ Single data-point in the life of a UniquePart
Each time something happens to the UniquePart, Each time something happens to the UniquePart,
a new PartTrackingInfo object should be created. a new PartTrackingInfo object should be created.
""" """
part = models.ForeignKey(UniquePart, on_delete=models.CASCADE) part = models.ForeignKey(UniquePart, on_delete=models.CASCADE)
date = models.DateField(auto_now_add=True, date = models.DateField(auto_now_add=True,
editable=False) editable=False)
notes = models.CharField(max_length=500) notes = models.CharField(max_length=500)