mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
API changes
- Allow SupplierPart to be filtered by 'company' in addition to 'supplier' and 'manufacturer' - Stock can now also be filtered by 'company'
This commit is contained in:
parent
635c4339e0
commit
1b1cd944be
@ -69,14 +69,6 @@ function loadCompanyTable(table, url, options={}) {
|
||||
return '';
|
||||
}
|
||||
},
|
||||
{
|
||||
field: 'part_count',
|
||||
title: 'Parts',
|
||||
sortable: true,
|
||||
formatter: function(value, row, index, field) {
|
||||
return renderLink(value, row.url + 'parts/');
|
||||
}
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
|
@ -81,12 +81,19 @@ class SupplierPartList(generics.ListCreateAPIView):
|
||||
|
||||
queryset = SupplierPart.objects.all().prefetch_related(
|
||||
'part',
|
||||
'part__category',
|
||||
'part__stock_items',
|
||||
'part__bom_items',
|
||||
'part__builds',
|
||||
'supplier',
|
||||
'pricebreaks')
|
||||
'manufacturer'
|
||||
)
|
||||
|
||||
def get_queryset(self):
|
||||
|
||||
queryset = super().get_queryset()
|
||||
|
||||
# Filter by EITHER manufacturer or supplier
|
||||
company = self.request.query_params.get('company', None)
|
||||
|
||||
if company is not None:
|
||||
queryset = queryset.filter(Q(manufacturer=company) | Q(supplier=company))
|
||||
|
||||
def get_serializer(self, *args, **kwargs):
|
||||
|
||||
|
@ -13,7 +13,7 @@ from decimal import Decimal
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django.core.validators import MinValueValidator
|
||||
from django.db import models
|
||||
from django.db.models import Sum
|
||||
from django.db.models import Sum, Q
|
||||
|
||||
from django.apps import apps
|
||||
from django.urls import reverse
|
||||
@ -140,26 +140,44 @@ class Company(models.Model):
|
||||
return getBlankThumbnail()
|
||||
|
||||
@property
|
||||
def part_count(self):
|
||||
def manufactured_part_count(self):
|
||||
""" The number of parts manufactured by this company """
|
||||
return self.manufactured_parts.count()
|
||||
|
||||
@property
|
||||
def has_manufactured_parts(self):
|
||||
return self.manufactured_part_count > 0
|
||||
|
||||
@property
|
||||
def supplied_part_count(self):
|
||||
""" The number of parts supplied by this company """
|
||||
return self.supplied_parts.count()
|
||||
|
||||
@property
|
||||
def has_supplied_parts(self):
|
||||
""" Return True if this company supplies any parts """
|
||||
return self.supplied_part_count > 0
|
||||
|
||||
@property
|
||||
def parts(self):
|
||||
""" Return SupplierPart objects which are supplied or manufactured by this company """
|
||||
return SupplierPart.objects.filter(Q(supplier=self.id) | Q(manufacturer=self.id))
|
||||
|
||||
@property
|
||||
def part_count(self):
|
||||
""" The number of parts manufactured (or supplied) by this Company """
|
||||
return self.parts.count()
|
||||
|
||||
@property
|
||||
def has_parts(self):
|
||||
""" Return True if this company supplies any parts """
|
||||
return self.part_count > 0
|
||||
|
||||
@property
|
||||
def stock_items(self):
|
||||
""" Return a list of all stock items supplied by this company """
|
||||
""" Return a list of all stock items supplied or manufactured by this company """
|
||||
stock = apps.get_model('stock', 'StockItem')
|
||||
return stock.objects.filter(supplier_part__supplier=self.id).all()
|
||||
return stock.objects.filter(Q(supplier_part__supplier=self.id) | Q(supplier_part__manufacturer=self.id)).all()
|
||||
|
||||
@property
|
||||
def stock_count(self):
|
||||
""" Return the number of stock items supplied by this company """
|
||||
stock = apps.get_model('stock', 'StockItem')
|
||||
return stock.objects.filter(supplier_part__supplier=self.id).count()
|
||||
""" Return the number of stock items supplied or manufactured by this company """
|
||||
return self.stock_items.count()
|
||||
|
||||
def outstanding_purchase_orders(self):
|
||||
""" Return purchase orders which are 'outstanding' """
|
||||
@ -255,7 +273,7 @@ class SupplierPart(models.Model):
|
||||
)
|
||||
|
||||
supplier = models.ForeignKey(Company, on_delete=models.CASCADE,
|
||||
related_name='parts',
|
||||
related_name='supplied_parts',
|
||||
limit_choices_to={'is_supplier': True},
|
||||
help_text=_('Select supplier'),
|
||||
)
|
||||
|
@ -6,8 +6,8 @@ Are you sure you want to delete company '{{ company.name }}'?
|
||||
|
||||
<br>
|
||||
|
||||
{% if company.part_count > 0 %}
|
||||
<p>There are {{ company.part_count }} parts sourced from this company.<br>
|
||||
{% if company.supplied_part_count > 0 %}
|
||||
<p>There are {{ company.supplied_part_count }} parts sourced from this company.<br>
|
||||
If this supplier is deleted, these supplier part entries will also be deleted.</p>
|
||||
<ul class='list-group'>
|
||||
{% for part in company.parts.all %}
|
||||
|
@ -12,15 +12,20 @@
|
||||
<col width='25'>
|
||||
<col>
|
||||
<tr>
|
||||
<td><span class='fas fa-user-tag'></span></td>
|
||||
<td>{% trans "Customer" %}</td>
|
||||
<td>{% include 'yesnolabel.html' with value=company.is_customer %}</td>
|
||||
<td><span class='fas fa-industry'></span></td>
|
||||
<td>{% trans "Manufacturer" %}</td>
|
||||
<td>{% include "yesnolabel.html" with value=company.is_manufacturer %}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><span class='fas fa-industry'></span></td>
|
||||
<td><span class='fas fa-building'></span></td>
|
||||
<td>{% trans "Supplier" %}</td>
|
||||
<td>{% include 'yesnolabel.html' with value=company.is_supplier %}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><span class='fas fa-user-tie'></span></td>
|
||||
<td>{% trans "Customer" %}</td>
|
||||
<td>{% include 'yesnolabel.html' with value=company.is_customer %}</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
{% endblock %}
|
||||
|
@ -19,8 +19,9 @@
|
||||
loadStockTable($('#stock-table'), {
|
||||
url: "{% url 'api-stock-list' %}",
|
||||
params: {
|
||||
supplier: {{ company.id }},
|
||||
company: {{ company.id }},
|
||||
part_detail: true,
|
||||
supplier_detail: true,
|
||||
location_detail: true,
|
||||
},
|
||||
buttons: [
|
||||
|
@ -4,13 +4,15 @@
|
||||
<li{% if tab == 'details' %} class='active'{% endif %}>
|
||||
<a href="{% url 'company-detail' company.id %}">{% trans "Details" %}</a>
|
||||
</li>
|
||||
{% if company.is_supplier %}
|
||||
{% if company.is_supplier or company.is_manufacturer %}
|
||||
<li{% if tab == 'parts' %} class='active'{% endif %}>
|
||||
<a href="{% url 'company-detail-parts' company.id %}">{% trans "Supplier Parts" %} <span class='badge'>{{ company.part_count }}</span></a>
|
||||
<a href="{% url 'company-detail-parts' company.id %}">{% trans "Parts" %} <span class='badge'>{{ company.part_count }}</span></a>
|
||||
</li>
|
||||
<li{% if tab == 'stock' %} class='active'{% endif %}>
|
||||
<a href="{% url 'company-detail-stock' company.id %}">{% trans "Stock" %} <span class='badge'>{{ company.stock_count }}</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if company.is_supplier %}
|
||||
<li{% if tab == 'po' %} class='active'{% endif %}>
|
||||
<a href="{% url 'company-detail-purchase-orders' company.id %}">{% trans "Purchase Orders" %} <span class='badge'>{{ company.purchase_orders.count }}</span></a>
|
||||
</li>
|
||||
|
@ -56,13 +56,13 @@ class CompanySimpleTest(TestCase):
|
||||
zerg = Company.objects.get(pk=3)
|
||||
|
||||
self.assertTrue(acme.has_parts)
|
||||
self.assertEqual(acme.part_count, 4)
|
||||
self.assertEqual(acme.supplied_part_count, 4)
|
||||
|
||||
self.assertTrue(appel.has_parts)
|
||||
self.assertEqual(appel.part_count, 2)
|
||||
self.assertEqual(appel.supplied_part_count, 2)
|
||||
|
||||
self.assertTrue(zerg.has_parts)
|
||||
self.assertEqual(zerg.part_count, 1)
|
||||
self.assertEqual(zerg.supplied_part_count, 1)
|
||||
|
||||
def test_price_breaks(self):
|
||||
|
||||
|
@ -15,7 +15,7 @@ company_detail_urls = [
|
||||
|
||||
# url(r'orders/?', views.CompanyDetail.as_view(template_name='company/orders.html'), name='company-detail-orders'),
|
||||
|
||||
url(r'parts/?', views.CompanyDetail.as_view(template_name='company/detail_part.html'), name='company-detail-parts'),
|
||||
url(r'parts/', views.CompanyDetail.as_view(template_name='company/detail_part.html'), name='company-detail-parts'),
|
||||
url(r'stock/?', views.CompanyDetail.as_view(template_name='company/detail_stock.html'), name='company-detail-stock'),
|
||||
url(r'purchase-orders/?', views.CompanyDetail.as_view(template_name='company/detail_purchase_orders.html'), name='company-detail-purchase-orders'),
|
||||
url(r'notes/?', views.CompanyNotes.as_view(), name='company-notes'),
|
||||
|
@ -8,6 +8,7 @@ from django_filters import NumberFilter
|
||||
from django.conf import settings
|
||||
from django.conf.urls import url, include
|
||||
from django.urls import reverse
|
||||
from django.db.models import Q
|
||||
|
||||
from .models import StockLocation, StockItem
|
||||
from .models import StockItemTracking
|
||||
@ -494,11 +495,23 @@ class StockList(generics.ListCreateAPIView):
|
||||
if supplier_part_id:
|
||||
stock_list = stock_list.filter(supplier_part=supplier_part_id)
|
||||
|
||||
# Filter by supplier ID
|
||||
supplier_id = self.request.query_params.get('supplier', None)
|
||||
# Filter by company (either manufacturer or supplier)
|
||||
company = self.request.query_params.get('company', None)
|
||||
|
||||
if supplier_id:
|
||||
stock_list = stock_list.filter(supplier_part__supplier=supplier_id)
|
||||
if company is not None:
|
||||
stock_list = stock_list.filter(Q(supplier_part__supplier=company) | Q(supplier_part__manufacturer=company))
|
||||
|
||||
# Filter by supplier
|
||||
supplier = self.request.query_params.get('supplier', None)
|
||||
|
||||
if supplier is not None:
|
||||
stock_list = stock_list.filter(supplier_part__supplier=supplier)
|
||||
|
||||
# Filter by manufacturer
|
||||
manufacturer = self.request.query_params.get('manufacturer', None)
|
||||
|
||||
if manufacturer is not None:
|
||||
stock_list = stock_list.filter(supplier_part__manufacturer=manufacturer)
|
||||
|
||||
# Also ensure that we pre-fecth all the related items
|
||||
stock_list = stock_list.prefetch_related(
|
||||
|
Loading…
Reference in New Issue
Block a user