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'
(cherry picked from commit 1b1cd944be
)
This commit is contained in:
parent
696c101628
commit
2506aa110b
@ -69,14 +69,6 @@ function loadCompanyTable(table, url, options={}) {
|
|||||||
return '';
|
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(
|
queryset = SupplierPart.objects.all().prefetch_related(
|
||||||
'part',
|
'part',
|
||||||
'part__category',
|
|
||||||
'part__stock_items',
|
|
||||||
'part__bom_items',
|
|
||||||
'part__builds',
|
|
||||||
'supplier',
|
'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):
|
def get_serializer(self, *args, **kwargs):
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ from decimal import Decimal
|
|||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from django.core.validators import MinValueValidator
|
from django.core.validators import MinValueValidator
|
||||||
from django.db import models
|
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.apps import apps
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
@ -140,26 +140,44 @@ class Company(models.Model):
|
|||||||
return getBlankThumbnail()
|
return getBlankThumbnail()
|
||||||
|
|
||||||
@property
|
@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 """
|
""" 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()
|
return self.parts.count()
|
||||||
|
|
||||||
@property
|
|
||||||
def has_parts(self):
|
|
||||||
""" Return True if this company supplies any parts """
|
|
||||||
return self.part_count > 0
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def stock_items(self):
|
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')
|
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
|
@property
|
||||||
def stock_count(self):
|
def stock_count(self):
|
||||||
""" Return the number of stock items supplied by this company """
|
""" Return the number of stock items supplied or manufactured by this company """
|
||||||
stock = apps.get_model('stock', 'StockItem')
|
return self.stock_items.count()
|
||||||
return stock.objects.filter(supplier_part__supplier=self.id).count()
|
|
||||||
|
|
||||||
def outstanding_purchase_orders(self):
|
def outstanding_purchase_orders(self):
|
||||||
""" Return purchase orders which are 'outstanding' """
|
""" Return purchase orders which are 'outstanding' """
|
||||||
@ -255,7 +273,7 @@ class SupplierPart(models.Model):
|
|||||||
)
|
)
|
||||||
|
|
||||||
supplier = models.ForeignKey(Company, on_delete=models.CASCADE,
|
supplier = models.ForeignKey(Company, on_delete=models.CASCADE,
|
||||||
related_name='parts',
|
related_name='supplied_parts',
|
||||||
limit_choices_to={'is_supplier': True},
|
limit_choices_to={'is_supplier': True},
|
||||||
help_text=_('Select supplier'),
|
help_text=_('Select supplier'),
|
||||||
)
|
)
|
||||||
|
@ -6,8 +6,8 @@ Are you sure you want to delete company '{{ company.name }}'?
|
|||||||
|
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
{% if company.part_count > 0 %}
|
{% if company.supplied_part_count > 0 %}
|
||||||
<p>There are {{ company.part_count }} parts sourced from this company.<br>
|
<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>
|
If this supplier is deleted, these supplier part entries will also be deleted.</p>
|
||||||
<ul class='list-group'>
|
<ul class='list-group'>
|
||||||
{% for part in company.parts.all %}
|
{% for part in company.parts.all %}
|
||||||
|
@ -12,15 +12,20 @@
|
|||||||
<col width='25'>
|
<col width='25'>
|
||||||
<col>
|
<col>
|
||||||
<tr>
|
<tr>
|
||||||
<td><span class='fas fa-user-tag'></span></td>
|
<td><span class='fas fa-industry'></span></td>
|
||||||
<td>{% trans "Customer" %}</td>
|
<td>{% trans "Manufacturer" %}</td>
|
||||||
<td>{% include 'yesnolabel.html' with value=company.is_customer %}</td>
|
<td>{% include "yesnolabel.html" with value=company.is_manufacturer %}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><span class='fas fa-industry'></span></td>
|
<td><span class='fas fa-building'></span></td>
|
||||||
<td>{% trans "Supplier" %}</td>
|
<td>{% trans "Supplier" %}</td>
|
||||||
<td>{% include 'yesnolabel.html' with value=company.is_supplier %}</td>
|
<td>{% include 'yesnolabel.html' with value=company.is_supplier %}</td>
|
||||||
</tr>
|
</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>
|
</table>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
@ -19,8 +19,9 @@
|
|||||||
loadStockTable($('#stock-table'), {
|
loadStockTable($('#stock-table'), {
|
||||||
url: "{% url 'api-stock-list' %}",
|
url: "{% url 'api-stock-list' %}",
|
||||||
params: {
|
params: {
|
||||||
supplier: {{ company.id }},
|
company: {{ company.id }},
|
||||||
part_detail: true,
|
part_detail: true,
|
||||||
|
supplier_detail: true,
|
||||||
location_detail: true,
|
location_detail: true,
|
||||||
},
|
},
|
||||||
buttons: [
|
buttons: [
|
||||||
|
@ -4,13 +4,15 @@
|
|||||||
<li{% if tab == 'details' %} class='active'{% endif %}>
|
<li{% if tab == 'details' %} class='active'{% endif %}>
|
||||||
<a href="{% url 'company-detail' company.id %}">{% trans "Details" %}</a>
|
<a href="{% url 'company-detail' company.id %}">{% trans "Details" %}</a>
|
||||||
</li>
|
</li>
|
||||||
{% if company.is_supplier %}
|
{% if company.is_supplier or company.is_manufacturer %}
|
||||||
<li{% if tab == 'parts' %} class='active'{% endif %}>
|
<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>
|
||||||
<li{% if tab == 'stock' %} class='active'{% endif %}>
|
<li{% if tab == 'stock' %} class='active'{% endif %}>
|
||||||
<a href="{% url 'company-detail-stock' company.id %}">{% trans "Stock" %} <span class='badge'>{{ company.stock_count }}</a>
|
<a href="{% url 'company-detail-stock' company.id %}">{% trans "Stock" %} <span class='badge'>{{ company.stock_count }}</a>
|
||||||
</li>
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
{% if company.is_supplier %}
|
||||||
<li{% if tab == 'po' %} class='active'{% endif %}>
|
<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>
|
<a href="{% url 'company-detail-purchase-orders' company.id %}">{% trans "Purchase Orders" %} <span class='badge'>{{ company.purchase_orders.count }}</span></a>
|
||||||
</li>
|
</li>
|
||||||
|
@ -56,13 +56,13 @@ class CompanySimpleTest(TestCase):
|
|||||||
zerg = Company.objects.get(pk=3)
|
zerg = Company.objects.get(pk=3)
|
||||||
|
|
||||||
self.assertTrue(acme.has_parts)
|
self.assertTrue(acme.has_parts)
|
||||||
self.assertEqual(acme.part_count, 4)
|
self.assertEqual(acme.supplied_part_count, 4)
|
||||||
|
|
||||||
self.assertTrue(appel.has_parts)
|
self.assertTrue(appel.has_parts)
|
||||||
self.assertEqual(appel.part_count, 2)
|
self.assertEqual(appel.supplied_part_count, 2)
|
||||||
|
|
||||||
self.assertTrue(zerg.has_parts)
|
self.assertTrue(zerg.has_parts)
|
||||||
self.assertEqual(zerg.part_count, 1)
|
self.assertEqual(zerg.supplied_part_count, 1)
|
||||||
|
|
||||||
def test_price_breaks(self):
|
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'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'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'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'),
|
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 import settings
|
||||||
from django.conf.urls import url, include
|
from django.conf.urls import url, include
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
|
from django.db.models import Q
|
||||||
|
|
||||||
from .models import StockLocation, StockItem
|
from .models import StockLocation, StockItem
|
||||||
from .models import StockItemTracking
|
from .models import StockItemTracking
|
||||||
@ -494,11 +495,23 @@ class StockList(generics.ListCreateAPIView):
|
|||||||
if supplier_part_id:
|
if supplier_part_id:
|
||||||
stock_list = stock_list.filter(supplier_part=supplier_part_id)
|
stock_list = stock_list.filter(supplier_part=supplier_part_id)
|
||||||
|
|
||||||
# Filter by supplier ID
|
# Filter by company (either manufacturer or supplier)
|
||||||
supplier_id = self.request.query_params.get('supplier', None)
|
company = self.request.query_params.get('company', None)
|
||||||
|
|
||||||
if supplier_id:
|
if company is not None:
|
||||||
stock_list = stock_list.filter(supplier_part__supplier=supplier_id)
|
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
|
# Also ensure that we pre-fecth all the related items
|
||||||
stock_list = stock_list.prefetch_related(
|
stock_list = stock_list.prefetch_related(
|
||||||
|
Loading…
Reference in New Issue
Block a user