mirror of
				https://github.com/inventree/InvenTree.git
				synced 2025-10-29 20:30:39 +00:00 
			
		
		
		
	| @@ -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 | ||||||
| @@ -88,12 +88,15 @@ class PartParameterTemplate(models.Model): | |||||||
|     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( | ||||||
|   | |||||||
| @@ -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) | ||||||
|   | |||||||
| @@ -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,18 +47,35 @@ 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.IntegerField(default=1) |     quantity = models.PositiveIntegerField(default=1) | ||||||
|     overage = models.FloatField(default=0) |     overage = models.FloatField(default=0) | ||||||
|     overage_type = models.IntegerField( |     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( | ||||||
|             name=self.part.name, |             name=self.part.name, | ||||||
|             quan=self.quantity) |             quan=self.quantity) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class ProjectRun(models.Model): | ||||||
|  |     """ A single run of a particular project. | ||||||
|  |     Tracks the number of 'units' made in the project. | ||||||
|  |     Provides functionality to update stock, | ||||||
|  |     based on both: | ||||||
|  |     a) Parts used (project inputs) | ||||||
|  |     b) Parts produced (project outputs) | ||||||
|  |     """ | ||||||
|  |  | ||||||
|  |     project = models.ForeignKey(Project, on_delete=models.CASCADE) | ||||||
|  |     quantity = models.PositiveIntegerField(default=1) | ||||||
|  |  | ||||||
|  |     run_date = models.DateField(auto_now_add=True) | ||||||
|   | |||||||
| @@ -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 | ||||||
| @@ -15,24 +15,39 @@ class StockItem(models.Model): | |||||||
|                              on_delete=models.CASCADE, |                              on_delete=models.CASCADE, | ||||||
|                              related_name='locations') |                              related_name='locations') | ||||||
|     location = models.ForeignKey(Warehouse, on_delete=models.CASCADE) |     location = models.ForeignKey(Warehouse, on_delete=models.CASCADE) | ||||||
|     quantity = models.IntegerField() |     quantity = models.PositiveIntegerField() | ||||||
|     updated = models.DateField(auto_now=True) |     updated = models.DateField(auto_now=True) | ||||||
|  |  | ||||||
|     # Stock status types |     # last time the stock was checked / counted | ||||||
|     ITEM_IN_PROGRESS = 0 |     last_checked = models.DateField(blank=True, null=True) | ||||||
|     ITEM_INCOMING = 5 |  | ||||||
|     ITEM_DAMAGED = 10 |  | ||||||
|     ITEM_ATTENTION = 20 |  | ||||||
|     ITEM_COMPLETE = 50 |  | ||||||
|  |  | ||||||
|     status = models.IntegerField(default=ITEM_IN_PROGRESS, |     review_needed = models.BooleanField(default=False) | ||||||
|                                  choices=[ |  | ||||||
|                                      (ITEM_IN_PROGRESS, "In progress"), |     # Stock status types | ||||||
|                                      (ITEM_INCOMING, "Incoming"), |     ITEM_IN_STOCK = 10 | ||||||
|                                      (ITEM_DAMAGED, "Damaged"), |     ITEM_INCOMING = 15 | ||||||
|                                      (ITEM_ATTENTION, "Requires attention"), |     ITEM_IN_PROGRESS = 20 | ||||||
|                                      (ITEM_COMPLETE, "Complete") |     ITEM_COMPLETE = 25 | ||||||
|                                  ]) |     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( | ||||||
|  |         default=ITEM_IN_STOCK, | ||||||
|  |         choices=ITEM_STATUS_CODES.items()) | ||||||
|  |  | ||||||
|  |     # If stock item is incoming, an (optional) ETA field | ||||||
|  |     expected_arrival = models.DateField(null=True, blank=True) | ||||||
|  |  | ||||||
|     def __str__(self): |     def __str__(self): | ||||||
|         return "{n} x {part} @ {loc}".format( |         return "{n} x {part} @ {loc}".format( | ||||||
|   | |||||||
| @@ -9,7 +9,6 @@ from part.models import Part | |||||||
| class Supplier(Company): | class Supplier(Company): | ||||||
|     """ Represents a manufacturer or supplier |     """ Represents a manufacturer or supplier | ||||||
|     """ |     """ | ||||||
|      |  | ||||||
|     pass |     pass | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -32,10 +31,8 @@ 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, related_name='supplier_parts') | ||||||
|                              on_delete=models.CASCADE) |     supplier = models.ForeignKey(Supplier, on_delete=models.CASCADE) | ||||||
|     supplier = models.ForeignKey(Supplier, |  | ||||||
|                                  on_delete=models.CASCADE) |  | ||||||
|     SKU = models.CharField(max_length=100) |     SKU = models.CharField(max_length=100) | ||||||
|  |  | ||||||
|     manufacturer = models.ForeignKey(Manufacturer, blank=True, null=True, on_delete=models.CASCADE) |     manufacturer = models.ForeignKey(Manufacturer, blank=True, null=True, on_delete=models.CASCADE) | ||||||
| @@ -44,9 +41,22 @@ class SupplierPart(models.Model): | |||||||
|     URL = models.URLField(blank=True) |     URL = models.URLField(blank=True) | ||||||
|     description = models.CharField(max_length=250, blank=True) |     description = models.CharField(max_length=250, blank=True) | ||||||
|  |  | ||||||
|  |     single_price = 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) | ||||||
|  |  | ||||||
|  |     # lead time for parts that cannot be delivered immediately | ||||||
|  |     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) | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -56,12 +66,9 @@ class SupplierPriceBreak(models.Model): | |||||||
|     - 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, related_name='price_breaks') | ||||||
|                              on_delete=models.CASCADE) |     quantity = models.PositiveIntegerField() | ||||||
|     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, |  | ||||||
|                                 blank=True) |  | ||||||
|  |  | ||||||
|     def __str__(self): |     def __str__(self): | ||||||
|         return "{mpn} - {cost}{currency} @ {quan}".format( |         return "{mpn} - {cost}{currency} @ {quan}".format( | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user