brandedpart can now have multiple parts (spelling variants, …)

master
agp8x 2018-02-22 17:34:28 +01:00
parent 772afa0016
commit 03f7bb86f5
4 changed files with 98 additions and 48 deletions

View File

@ -10,11 +10,11 @@ class BrandedPartInline(admin.StackedInline):
model = BrandedPart
extra = 1
search_fields = ["number", "name"]
autocomplete_fields = ["part"]
autocomplete_fields = ["parts"]
class PartAdmin(admin.ModelAdmin):
inlines = [BrandedPartInline]
#inlines = [BrandedPartInline]
search_fields = ["name"]
@ -48,7 +48,7 @@ class UsageInline(admin.StackedInline):
class BrandedPartAdmin(admin.ModelAdmin):
inlines = [UsageInline]
search_fields = ["number"]
autocomplete_fields = ["part"]
autocomplete_fields = ["parts"]
admin.site.register(Usage, UsageAdmin)

View File

@ -1,4 +1,5 @@
from django.db import models
from django.db import models, transaction
class PartModel(models.Model):
creation = models.DateTimeField(auto_now_add=True)
@ -26,6 +27,7 @@ class Product(PartModel):
class Sketch(PartModel):
class Meta:
verbose_name_plural = "sketches"
name = models.CharField(max_length=256)
brand = models.ForeignKey(Brand, blank=True, null=True, on_delete=models.CASCADE, db_index=True)
product = models.ForeignKey(Product, blank=True, null=True, on_delete=models.CASCADE)
@ -38,6 +40,7 @@ class Sketch(PartModel):
if self.product:
return [self.product] + list(self.usage_set.values('productusage__product').distinct())
return self.usage_set.values('productusage__product').distinct()
def get_brand(self):
if self.brand:
return [self.brand] + list(self.usage_set.values('productusage__product__brand').distinct())
@ -64,16 +67,45 @@ class Part(PartModel):
def __str__(self):
return self.name
class BrandedPart(PartModel):
part = models.ForeignKey(Part, null=True, on_delete=models.SET_NULL, db_index=True)
parts = models.ManyToManyField(Part, db_index=True, related_name="branded_parts")
brand = models.ForeignKey(Brand, on_delete=models.CASCADE)
number = models.CharField(max_length=64, unique=True, blank=True, null=True, db_index=True)
def get_name(self):
return self.part.name if self.part else "--None--"
@transaction.atomic
def _merge(self, other):
"""add other part's usages and delete it"""
for p in other.parts.all():
if not p in self.parts.all():
self.parts.add(p)
self.save()
for u in other.usage_set.all():
u.part = self
u.save()
other.delete()
@staticmethod
@transaction.atomic
def merge(number1, number2):
self = BrandedPart.objects.filter(number=number1)
other = BrandedPart.objects.filter(number=number2)
if not (self and other):
raise ValueError("invalid arguments! {} {}".format(self, other))
self[0]._merge(other[0])
def get_part_name(self):
return self.parts.first().name if len(self.parts) else ""
def get_name(self, full=False, first=False):
if full:
return ", ".join([i.name for i in self.parts.all()])
if first:
return self.parts.first().name if self.parts else "--(parts)--"
return "{} ({})".format(self.parts.first().name, self.parts.count()) if self.parts else "--(parts)--"
def __str__(self):
na = self.part.name if self.part else "--(part)--"
na = self.get_name() if self.parts else "--(part)--"
return str(self.number) + ": " + na + " @ " + self.brand.name
@ -82,16 +114,17 @@ class Usage(PartModel):
sketch = models.ForeignKey(Sketch, on_delete=models.CASCADE, db_index=True)
sketch_number = models.CharField(max_length=32)
exact_sketch = models.BooleanField(default=True)
# quantity = models.ManyToManyField(ProductUsage)
def __str__(self):
no = self.part.number if self.part else "--(part.number)--"
na = self.part.part.name if self.part.part else "--(part.part.name)--"
na = self.part.get_name() if self.part else "--(part.part.name)--"
return self.sketch_number + "; " + str(no) + "; " + na + "; " + str(self.sketch)
class ProductUsage(PartModel):
usage = models.ForeignKey(Usage, null=True, on_delete=models.SET_NULL, db_index=True)
usage = models.ForeignKey(Usage, on_delete=models.CASCADE, db_index=True)
product = models.ForeignKey(Product, on_delete=models.CASCADE, db_index=True)
quantity = models.IntegerField(null=True)
on_demand = models.BooleanField(default=False)

View File

@ -15,6 +15,7 @@
{% csrf_token %}
<input type="submit"/>
<p><label for="sketch_name">Name:</label><input type="text" name="sketch_name" value="{{ sketch.name }}"/></p>
<button type="button" onclick="addRow()">add row</button>
<table id="table">
<tr>
<th>Bild-Nr.</th>
@ -34,7 +35,7 @@
<td>{{ usage.sketch_number }}</td>
<td>{{ usage.part.number }}</td>
<td>{{ productusage.internal_note }}</td>
<td>{{ usage.part.part.name }}</td>
<td>{{ usage.part.get_name }}</td>
<td>{{ productusage.quantity }}</td>
<td>{{ productusage.used_until }}</td>
<td>{{ productusage.used_since }}</td>
@ -47,7 +48,6 @@
{% endif %}
</table>
</form>
<button type="button" onclick="addRow()">add row</button>
<table style="display:none;">
<tr id="template">
<td><input type="text" size="8" name="fignumber"/></td>

View File

@ -8,22 +8,26 @@ from .models import *
ADD_SKETCH_REQUIRES = ['sketch_name', 'sketch_number', '']
def index(request):
product_list = Product.objects.all()
context = {'product_list': product_list}
return render(request, 'parts/products.html', context)
def product(request, product_id):
product = Product.objects.get(id=product_id)
sketches = Sketch.objects.filter(usage__productusage__product=product)
context = {'product': product, 'sketches': sketches}
return render(request, 'parts/product.html', context)
def sketch(request, sketch_id):
sketch = Sketch.objects.get(id=sketch_id)
context = {'sketch': sketch}
return render(request, 'parts/sketch.html', context)
def part_search(request):
if "term" in request.GET:
term = request.GET.get("term", '')
@ -33,15 +37,17 @@ def part_search(request):
[
{
'id': part.id,
'label':part.number + " - " + part.get_name(),
'label': part.number + " - " + part.get_name(full=True),
'value': part.number,
'name':part.get_name()
'name': part.get_name(first=True)
}
for part in parts],
for part in parts
],
indent=1)
)
return HttpResponse("404")
@transaction.atomic
def sketch_add(request, product_id, sketch_id=None):
product = get_object_or_404(Product, pk=product_id)
@ -67,14 +73,24 @@ def sketch_add(request, product_id, sketch_id=None):
if len(part_number) < 1:
continue
branded_part, created = BrandedPart.objects.get_or_create(brand=product.brand, number=part_number)
_part_name = request.POST.getlist('name')[i].strip()
if created:
try:
part, _ = Part.objects.get_or_create(name=request.POST.getlist('name')[i])
part, _ = Part.objects.get_or_create(name=_part_name)
except Part.MultipleObjectsReturned:
part = Part.objects.filter(name=request.POST.getlist('name')[i]).first()
branded_part.part = part
part = Part.objects.filter(name=_part_name).first()
branded_part.parts.add(part)
branded_part.brand = product.brand
branded_part.save()
else:
if len(_part_name):
part = Part.objects.filter(name=_part_name)
if not (part and part.first() in branded_part.parts.all()):
if part:
branded_part.parts.add(part.first())
else:
part, _ = Part.objects.get_or_create(name=_part_name)
branded_part.parts.add(part)
usage.part = branded_part
usage.save()
@ -112,6 +128,7 @@ def get_quantity(qnty_str):
qnty = int(qnty_str)
return qnty
def is_exact_sketchnumber(sketch_number):
approximate = ("ähn", "vgl", "~", "zu")
return not any([i in sketch_number for i in approximate])