Merge pull request #297 from SchrodingersGat/field-doc

Field doc
This commit is contained in:
Oliver 2019-05-10 20:18:51 +10:00 committed by GitHub
commit 164f98540d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 124 additions and 60 deletions

View File

@ -17,6 +17,11 @@ class InvenTreeTree(models.Model):
- 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)
Attributes:
name: brief name
description: longer form description
parent: The item immediately above this one. An item with a null parent is a top-level item
""" """
class Meta: class Meta:

View File

@ -342,7 +342,7 @@ class BuildItem(models.Model):
Attributes: Attributes:
build: Link to a Build object build: Link to a Build object
stock: Link to a StockItem object stock_item: Link to a StockItem object
quantity: Number of units allocated quantity: Number of units allocated
""" """

View File

@ -42,6 +42,19 @@ def rename_company_image(instance, filename):
class Company(models.Model): class Company(models.Model):
""" A Company object represents an external company. """ A Company object represents an external company.
It may be a supplier or a customer (or both). It may be a supplier or a customer (or both).
Attributes:
name: Brief name of the company
description: Longer form description
website: URL for the company website
address: Postal address
phone: contact phone number
email: contact email address
URL: Secondary URL e.g. for link to internal Wiki page
image: Company image / logo
notes: Extra notes about the company
is_customer: boolean value, is this company a customer
is_supplier: boolean value, is this company a supplier
""" """
name = models.CharField(max_length=100, blank=False, unique=True, name = models.CharField(max_length=100, blank=False, unique=True,
@ -101,9 +114,19 @@ class Company(models.Model):
class Contact(models.Model): class Contact(models.Model):
""" A Contact represents a person who works at a particular company. """ A Contact represents a person who works at a particular company.
A Company may have zero or more associated Contact objects A Company may have zero or more associated Contact objects.
Attributes:
company: Company link for this contact
name: Name of the contact
phone: contact phone number
email: contact email
role: position in company
""" """
company = models.ForeignKey(Company, related_name='contacts',
on_delete=models.CASCADE)
name = models.CharField(max_length=100) name = models.CharField(max_length=100)
phone = models.CharField(max_length=100, blank=True) phone = models.CharField(max_length=100, blank=True)

View File

@ -116,9 +116,30 @@ def rename_part_image(instance, filename):
class Part(models.Model): class Part(models.Model):
""" Represents an abstract part """ The Part object represents an abstract part, the 'concept' of an actual entity.
Parts can be "stocked" in multiple warehouses,
and can be combined to form other parts An actual physical instance of a Part is a StockItem which is treated separately.
Parts can be used to create other parts (as part of a Bill of Materials or BOM).
Attributes:
name: Brief name for this part
description: Longer form description of the part
category: The PartCategory to which this part belongs
IPN: Internal part number (optional)
URL: Link to an external page with more information about this part (e.g. internal Wiki)
image: Image of this part
default_location: Where the item is normally stored (may be null)
default_supplier: The default SupplierPart which should be used to procure and stock this part
minimum_stock: Minimum preferred quantity to keep in stock
units: Units of measure for this part (default='pcs')
salable: Can this part be sold to customers?
buildable: Can this part be build from other parts?
consumable: Can this part be used to make other parts?
purchaseable: Can this part be purchased from suppliers?
trackable: Trackable parts can have unique serial numbers assigned, etc, etc
active: Is this part active? Parts are deactivated instead of being deleted
notes: Additional notes field for this part
""" """
def get_absolute_url(self): def get_absolute_url(self):
@ -133,26 +154,19 @@ class Part(models.Model):
else: else:
return static('/img/blank_image.png') return static('/img/blank_image.png')
# Short name of the part
name = models.CharField(max_length=100, unique=True, blank=False, help_text='Part name (must be unique)') name = models.CharField(max_length=100, unique=True, blank=False, help_text='Part name (must be unique)')
# Longer description of the part (optional)
description = models.CharField(max_length=250, blank=False, help_text='Part description') description = models.CharField(max_length=250, blank=False, help_text='Part description')
# Internal Part Number (optional)
# Potentially multiple parts map to the same internal IPN (variants?)
# So this does not have to be unique
IPN = models.CharField(max_length=100, blank=True, help_text='Internal Part Number')
# Provide a URL for an external link
URL = models.URLField(blank=True, help_text='Link to extenal URL')
# Part category - all parts must be assigned to a category
category = models.ForeignKey(PartCategory, related_name='parts', category = models.ForeignKey(PartCategory, related_name='parts',
null=True, blank=True, null=True, blank=True,
on_delete=models.DO_NOTHING, on_delete=models.DO_NOTHING,
help_text='Part category') help_text='Part category')
IPN = models.CharField(max_length=100, blank=True, help_text='Internal Part Number')
URL = models.URLField(blank=True, help_text='Link to extenal URL')
image = models.ImageField(upload_to=rename_part_image, max_length=255, null=True, blank=True) image = models.ImageField(upload_to=rename_part_image, max_length=255, null=True, blank=True)
default_location = models.ForeignKey('stock.StockLocation', on_delete=models.SET_NULL, default_location = models.ForeignKey('stock.StockLocation', on_delete=models.SET_NULL,
@ -183,23 +197,18 @@ class Part(models.Model):
# Default case - no default category found # Default case - no default category found
return None return None
# Default supplier part
default_supplier = models.ForeignKey('part.SupplierPart', default_supplier = models.ForeignKey('part.SupplierPart',
on_delete=models.SET_NULL, on_delete=models.SET_NULL,
blank=True, null=True, blank=True, null=True,
help_text='Default supplier part', help_text='Default supplier part',
related_name='default_parts') related_name='default_parts')
# Minimum "allowed" stock level
minimum_stock = models.PositiveIntegerField(default=0, validators=[MinValueValidator(0)], help_text='Minimum allowed stock level') minimum_stock = models.PositiveIntegerField(default=0, validators=[MinValueValidator(0)], help_text='Minimum allowed stock level')
# Units of quantity for this part. Default is "pcs"
units = models.CharField(max_length=20, default="pcs", blank=True, help_text='Stock keeping units for this part') units = models.CharField(max_length=20, default="pcs", blank=True, help_text='Stock keeping units for this part')
# Can this part be built from other parts?
buildable = models.BooleanField(default=False, help_text='Can this part be built from other parts?') buildable = models.BooleanField(default=False, help_text='Can this part be built from other parts?')
# Can this part be used to make other parts?
consumable = models.BooleanField(default=True, help_text='Can this part be used to build other parts?') consumable = models.BooleanField(default=True, help_text='Can this part be used to build other parts?')
# Is this part "trackable"? # Is this part "trackable"?
@ -434,6 +443,11 @@ def attach_file(instance, filename):
class PartAttachment(models.Model): class PartAttachment(models.Model):
""" A PartAttachment links a file to a part """ A PartAttachment links a file to a part
Parts can have multiple files such as datasheets, etc Parts can have multiple files such as datasheets, etc
Attributes:
part: Link to a Part object
attachment: File
comment: String descriptor for the attachment
""" """
part = models.ForeignKey(Part, on_delete=models.CASCADE, part = models.ForeignKey(Part, on_delete=models.CASCADE,
@ -454,6 +468,10 @@ class PartStar(models.Model):
It is used to designate a Part as 'starred' (or favourited) for a given User, It is used to designate a Part as 'starred' (or favourited) for a given User,
so that the user can track a list of their favourite parts. so that the user can track a list of their favourite parts.
Attributes:
part: Link to a Part object
user: Link to a User object
""" """
part = models.ForeignKey(Part, on_delete=models.CASCADE, related_name='starred_users') part = models.ForeignKey(Part, on_delete=models.CASCADE, related_name='starred_users')
@ -467,7 +485,13 @@ class PartStar(models.Model):
class BomItem(models.Model): class BomItem(models.Model):
""" A BomItem links a part to its component items. """ A BomItem links a part to its component items.
A part can have a BOM (bill of materials) which defines A part can have a BOM (bill of materials) which defines
which parts are required (and in what quatity) to make it which parts are required (and in what quatity) to make it.
Attributes:
part: Link to the parent part (the part that will be produced)
sub_part: Link to the child part (the part that will be consumed)
quantity: Number of 'sub_parts' consumed to produce one 'part'
note: Note field for this BOM item
""" """
def get_absolute_url(self): def get_absolute_url(self):
@ -530,8 +554,23 @@ 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
Attributes:
part: Link to the master Part
supplier: Company that supplies this SupplierPart object
SKU: Stock keeping unit (supplier part number)
manufacturer: Manufacturer name
MPN: Manufacture part number
URL: Link to external website for this part
description: Descriptive notes field
note: Longer form note field
single_price: Default price for a single unit
base_cost: Base charge added to order independent of quantity e.g. "Reeling Fee"
multiple: Multiple that the part is provided in
minimum: MOQ (minimum order quantity) required for purchase
lead_time: Supplier lead time
packaging: packaging that the part is supplied in, e.g. "Reel"
""" """
def get_absolute_url(self): def get_absolute_url(self):
@ -540,8 +579,6 @@ class SupplierPart(models.Model):
class Meta: class Meta:
unique_together = ('part', 'supplier', 'SKU') 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, part = models.ForeignKey(Part, on_delete=models.CASCADE,
related_name='supplier_parts', related_name='supplier_parts',
limit_choices_to={'purchaseable': True}, limit_choices_to={'purchaseable': True},
@ -564,25 +601,18 @@ class SupplierPart(models.Model):
description = models.CharField(max_length=250, blank=True, help_text='Supplier part description') description = models.CharField(max_length=250, blank=True, help_text='Supplier part description')
# Note attached to this BOM line item
note = models.CharField(max_length=100, blank=True, help_text='Notes') note = models.CharField(max_length=100, blank=True, help_text='Notes')
# Default price for a single unit
single_price = models.DecimalField(max_digits=10, decimal_places=3, default=0, validators=[MinValueValidator(0)], help_text='Price for single quantity') single_price = models.DecimalField(max_digits=10, decimal_places=3, default=0, validators=[MinValueValidator(0)], help_text='Price for single quantity')
# Base charge added to order independent of quantity e.g. "Reeling Fee"
base_cost = models.DecimalField(max_digits=10, decimal_places=3, default=0, validators=[MinValueValidator(0)], help_text='Minimum charge (e.g. stocking fee)') base_cost = models.DecimalField(max_digits=10, decimal_places=3, default=0, validators=[MinValueValidator(0)], help_text='Minimum charge (e.g. stocking fee)')
# packaging that the part is supplied in, e.g. "Reel"
packaging = models.CharField(max_length=50, blank=True, help_text='Part packaging') packaging = models.CharField(max_length=50, blank=True, help_text='Part packaging')
# multiple that the part is provided in
multiple = models.PositiveIntegerField(default=1, validators=[MinValueValidator(1)], help_text='Order multiple') multiple = models.PositiveIntegerField(default=1, validators=[MinValueValidator(1)], help_text='Order multiple')
# Mimumum number required to order
minimum = models.PositiveIntegerField(default=1, validators=[MinValueValidator(1)], help_text='Minimum order quantity (MOQ)') minimum = models.PositiveIntegerField(default=1, validators=[MinValueValidator(1)], help_text='Minimum order quantity (MOQ)')
# lead time for parts that cannot be delivered immediately
lead_time = models.DurationField(blank=True, null=True) lead_time = models.DurationField(blank=True, null=True)
@property @property
@ -654,9 +684,14 @@ class SupplierPart(models.Model):
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)
Attributes:
part: Link to a SupplierPart object that this price break applies to
quantity: Quantity required for price break
cost: Cost at specified quantity
""" """
part = models.ForeignKey(SupplierPart, on_delete=models.CASCADE, related_name='price_breaks') part = models.ForeignKey(SupplierPart, on_delete=models.CASCADE, related_name='price_breaks')

View File

@ -77,10 +77,23 @@ def before_delete_stock_location(sender, instance, using, **kwargs):
class StockItem(models.Model): class StockItem(models.Model):
""" """
A 'StockItem' instance represents a quantity of physical instances of a part. A StockItem object represents a quantity of physical instances of a part.
It may exist in a StockLocation, or as part of a sub-assembly installed into another StockItem
StockItems may be tracked using batch or serial numbers. Attributes:
If a serial number is assigned, then StockItem cannot have a quantity other than 1 part: Link to the master abstract part that this StockItem is an instance of
supplier_part: Link to a specific SupplierPart (optional)
location: Where this StockItem is located
quantity: Number of stocked units
batch: Batch number for this StockItem
URL: Optional URL to link to external resource
updated: Date that this stock item was last updated (auto)
stocktake_date: Date of last stocktake for this item
stocktake_user: User that performed the most recent stocktake
review_needed: Flag if StockItem needs review
delete_on_deplete: If True, StockItem will be deleted when the stock level gets to zero
status: Status of this StockItem (ref: ITEM_STATUS_CODES)
notes: Extra notes field
infinite: If True this StockItem can never be exhausted
""" """
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
@ -171,46 +184,33 @@ class StockItem(models.Model):
} }
) )
# The 'master' copy of the part of which this stock item is an instance
part = models.ForeignKey('part.Part', on_delete=models.CASCADE, related_name='locations', help_text='Base part') part = models.ForeignKey('part.Part', on_delete=models.CASCADE, related_name='locations', help_text='Base part')
# The 'supplier part' used in this instance. May be null if no supplier parts are defined the master part
supplier_part = models.ForeignKey('part.SupplierPart', blank=True, null=True, on_delete=models.SET_NULL, supplier_part = models.ForeignKey('part.SupplierPart', blank=True, null=True, on_delete=models.SET_NULL,
help_text='Select a matching supplier part for this stock item') help_text='Select a matching supplier part for this stock item')
# Where the part is stored. If the part has been used to build another stock item, the location may not make sense
location = models.ForeignKey(StockLocation, on_delete=models.DO_NOTHING, location = models.ForeignKey(StockLocation, on_delete=models.DO_NOTHING,
related_name='stock_items', blank=True, null=True, related_name='stock_items', blank=True, null=True,
help_text='Where is this stock item located?') help_text='Where is this stock item located?')
# If this StockItem belongs to another StockItem (e.g. as part of a sub-assembly)
belongs_to = models.ForeignKey('self', on_delete=models.DO_NOTHING, belongs_to = models.ForeignKey('self', on_delete=models.DO_NOTHING,
related_name='owned_parts', blank=True, null=True, related_name='owned_parts', blank=True, null=True,
help_text='Is this item installed in another item?') help_text='Is this item installed in another item?')
# The StockItem may be assigned to a particular customer
customer = models.ForeignKey('company.Company', on_delete=models.SET_NULL, customer = models.ForeignKey('company.Company', on_delete=models.SET_NULL,
related_name='stockitems', blank=True, null=True, related_name='stockitems', blank=True, null=True,
help_text='Item assigned to customer?') help_text='Item assigned to customer?')
# Optional serial number
serial = models.PositiveIntegerField(blank=True, null=True, serial = models.PositiveIntegerField(blank=True, null=True,
help_text='Serial number for this item') help_text='Serial number for this item')
# Optional URL to link to external resource
URL = models.URLField(max_length=125, blank=True) URL = models.URLField(max_length=125, blank=True)
# Optional batch information
batch = models.CharField(max_length=100, blank=True, null=True, batch = models.CharField(max_length=100, blank=True, null=True,
help_text='Batch code for this stock item') help_text='Batch code for this stock item')
# If this part was produced by a build, point to that build here
# build = models.ForeignKey('build.Build', on_delete=models.SET_NULL, blank=True, null=True)
# Quantity of this stock item. Value may be overridden by other settings
quantity = models.PositiveIntegerField(validators=[MinValueValidator(0)], default=1) quantity = models.PositiveIntegerField(validators=[MinValueValidator(0)], default=1)
# Last time this item was updated (set automagically)
updated = models.DateField(auto_now=True) updated = models.DateField(auto_now=True)
# last time the stock was checked / counted # last time the stock was checked / counted
@ -409,33 +409,34 @@ class StockItem(models.Model):
class StockItemTracking(models.Model): class StockItemTracking(models.Model):
""" Stock tracking entry """ Stock tracking entry - breacrumb for keeping track of automated stock transactions
Attributes:
item: Link to StockItem
date: Date that this tracking info was created
title: Title of this tracking info (generated by system)
notes: Associated notes (input by user)
user: The user associated with this tracking info
quantity: The StockItem quantity at this point in time
""" """
def get_absolute_url(self): def get_absolute_url(self):
return '/stock/track/{pk}'.format(pk=self.id) return '/stock/track/{pk}'.format(pk=self.id)
# return reverse('stock-tracking-detail', kwargs={'pk': self.id}) # return reverse('stock-tracking-detail', kwargs={'pk': self.id})
# Stock item
item = models.ForeignKey(StockItem, on_delete=models.CASCADE, item = models.ForeignKey(StockItem, on_delete=models.CASCADE,
related_name='tracking_info') related_name='tracking_info')
# Date this entry was created (cannot be edited)
date = models.DateTimeField(auto_now_add=True, editable=False) date = models.DateTimeField(auto_now_add=True, editable=False)
# Short-form title for this tracking entry
title = models.CharField(blank=False, max_length=250) title = models.CharField(blank=False, max_length=250)
# Optional longer description
notes = models.TextField(blank=True) notes = models.TextField(blank=True)
# Which user created this tracking entry?
user = models.ForeignKey(User, on_delete=models.SET_NULL, blank=True, null=True) user = models.ForeignKey(User, on_delete=models.SET_NULL, blank=True, null=True)
# Was this tracking note auto-generated by the system?
system = models.BooleanField(default=False) system = models.BooleanField(default=False)
# Keep track of the StockItem quantity throughout the tracking history
quantity = models.PositiveIntegerField(validators=[MinValueValidator(0)], default=1) quantity = models.PositiveIntegerField(validators=[MinValueValidator(0)], default=1)
# TODO # TODO