mirror of
				https://github.com/inventree/InvenTree.git
				synced 2025-11-04 07:05:41 +00:00 
			
		
		
		
	Merge remote-tracking branch 'inventree/master'
This commit is contained in:
		@@ -12,11 +12,14 @@ import common.models
 | 
				
			|||||||
INVENTREE_SW_VERSION = "0.7.0 dev"
 | 
					INVENTREE_SW_VERSION = "0.7.0 dev"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# InvenTree API version
 | 
					# InvenTree API version
 | 
				
			||||||
INVENTREE_API_VERSION = 37
 | 
					INVENTREE_API_VERSION = 38
 | 
				
			||||||
 | 
					
 | 
				
			||||||
"""
 | 
					"""
 | 
				
			||||||
Increment this API version number whenever there is a significant change to the API that any clients need to know about
 | 
					Increment this API version number whenever there is a significant change to the API that any clients need to know about
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					v38 -> 2022-04-14 : https://github.com/inventree/InvenTree/pull/2828
 | 
				
			||||||
 | 
					    - Adds the ability to include stock test results for "installed items"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
v37 -> 2022-04-07 : https://github.com/inventree/InvenTree/pull/2806
 | 
					v37 -> 2022-04-07 : https://github.com/inventree/InvenTree/pull/2806
 | 
				
			||||||
    - Adds extra stock availability information to the BomItem serializer
 | 
					    - Adds extra stock availability information to the BomItem serializer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1313,19 +1313,31 @@ class Part(MPTTModel):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        return quantity
 | 
					        return quantity
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def build_order_allocations(self):
 | 
					    def build_order_allocations(self, **kwargs):
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        Return all 'BuildItem' objects which allocate this part to Build objects
 | 
					        Return all 'BuildItem' objects which allocate this part to Build objects
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return BuildModels.BuildItem.objects.filter(stock_item__part__id=self.id)
 | 
					        include_variants = kwargs.get('include_variants', True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def build_order_allocation_count(self):
 | 
					        queryset = BuildModels.BuildItem.objects.all()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if include_variants:
 | 
				
			||||||
 | 
					            variants = self.get_descendants(include_self=True)
 | 
				
			||||||
 | 
					            queryset = queryset.filter(
 | 
				
			||||||
 | 
					                stock_item__part__in=variants,
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            queryset = queryset.filter(stock_item__part=self)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return queryset
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def build_order_allocation_count(self, **kwargs):
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        Return the total amount of this part allocated to build orders
 | 
					        Return the total amount of this part allocated to build orders
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        query = self.build_order_allocations().aggregate(
 | 
					        query = self.build_order_allocations(**kwargs).aggregate(
 | 
				
			||||||
            total=Coalesce(
 | 
					            total=Coalesce(
 | 
				
			||||||
                Sum(
 | 
					                Sum(
 | 
				
			||||||
                    'quantity',
 | 
					                    'quantity',
 | 
				
			||||||
@@ -1343,7 +1355,19 @@ class Part(MPTTModel):
 | 
				
			|||||||
        Return all sales-order-allocation objects which allocate this part to a SalesOrder
 | 
					        Return all sales-order-allocation objects which allocate this part to a SalesOrder
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        queryset = OrderModels.SalesOrderAllocation.objects.filter(item__part__id=self.id)
 | 
					        include_variants = kwargs.get('include_variants', True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        queryset = OrderModels.SalesOrderAllocation.objects.all()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if include_variants:
 | 
				
			||||||
 | 
					            # Include allocations for all variants
 | 
				
			||||||
 | 
					            variants = self.get_descendants(include_self=True)
 | 
				
			||||||
 | 
					            queryset = queryset.filter(
 | 
				
			||||||
 | 
					                item__part__in=variants,
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            # Only look at this part
 | 
				
			||||||
 | 
					            queryset = queryset.filter(item__part=self)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Default behaviour is to only return *pending* allocations
 | 
					        # Default behaviour is to only return *pending* allocations
 | 
				
			||||||
        pending = kwargs.get('pending', True)
 | 
					        pending = kwargs.get('pending', True)
 | 
				
			||||||
@@ -1381,7 +1405,7 @@ class Part(MPTTModel):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        return query['total']
 | 
					        return query['total']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def allocation_count(self):
 | 
					    def allocation_count(self, **kwargs):
 | 
				
			||||||
        """
 | 
					        """
 | 
				
			||||||
        Return the total quantity of stock allocated for this part,
 | 
					        Return the total quantity of stock allocated for this part,
 | 
				
			||||||
        against both build orders and sales orders.
 | 
					        against both build orders and sales orders.
 | 
				
			||||||
@@ -1389,8 +1413,8 @@ class Part(MPTTModel):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        return sum(
 | 
					        return sum(
 | 
				
			||||||
            [
 | 
					            [
 | 
				
			||||||
                self.build_order_allocation_count(),
 | 
					                self.build_order_allocation_count(**kwargs),
 | 
				
			||||||
                self.sales_order_allocation_count(),
 | 
					                self.sales_order_allocation_count(**kwargs),
 | 
				
			||||||
            ],
 | 
					            ],
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -252,7 +252,6 @@
 | 
				
			|||||||
        </tr>
 | 
					        </tr>
 | 
				
			||||||
        {% endif %}
 | 
					        {% endif %}
 | 
				
			||||||
        {% endif %}
 | 
					        {% endif %}
 | 
				
			||||||
        {% if not part.is_template %}
 | 
					 | 
				
			||||||
        {% if part.assembly %}
 | 
					        {% if part.assembly %}
 | 
				
			||||||
        <tr>
 | 
					        <tr>
 | 
				
			||||||
            <td><span class='fas fa-tools'></span></td>
 | 
					            <td><span class='fas fa-tools'></span></td>
 | 
				
			||||||
@@ -266,7 +265,6 @@
 | 
				
			|||||||
            <td>{% decimal quantity_being_built %}</td>
 | 
					            <td>{% decimal quantity_being_built %}</td>
 | 
				
			||||||
        </tr>
 | 
					        </tr>
 | 
				
			||||||
        {% endif %}
 | 
					        {% endif %}
 | 
				
			||||||
        {% endif %}
 | 
					 | 
				
			||||||
    {% endif %}
 | 
					    {% endif %}
 | 
				
			||||||
</table>
 | 
					</table>
 | 
				
			||||||
{% endblock details_right %}
 | 
					{% endblock details_right %}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1105,7 +1105,6 @@ class StockItemTestResultList(generics.ListCreateAPIView):
 | 
				
			|||||||
    ]
 | 
					    ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    filter_fields = [
 | 
					    filter_fields = [
 | 
				
			||||||
        'stock_item',
 | 
					 | 
				
			||||||
        'test',
 | 
					        'test',
 | 
				
			||||||
        'user',
 | 
					        'user',
 | 
				
			||||||
        'result',
 | 
					        'result',
 | 
				
			||||||
@@ -1114,6 +1113,38 @@ class StockItemTestResultList(generics.ListCreateAPIView):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    ordering = 'date'
 | 
					    ordering = 'date'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def filter_queryset(self, queryset):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        params = self.request.query_params
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        queryset = super().filter_queryset(queryset)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Filter by stock item
 | 
				
			||||||
 | 
					        item = params.get('stock_item', None)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if item is not None:
 | 
				
			||||||
 | 
					            try:
 | 
				
			||||||
 | 
					                item = StockItem.objects.get(pk=item)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                items = [item]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                # Do we wish to also include test results for 'installed' items?
 | 
				
			||||||
 | 
					                include_installed = str2bool(params.get('include_installed', False))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if include_installed:
 | 
				
			||||||
 | 
					                    # Include items which are installed "underneath" this item
 | 
				
			||||||
 | 
					                    # Note that this function is recursive!
 | 
				
			||||||
 | 
					                    installed_items = item.get_installed_items(cascade=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    items += [it for it in installed_items]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                queryset = queryset.filter(stock_item__in=items)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            except (ValueError, StockItem.DoesNotExist):
 | 
				
			||||||
 | 
					                pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return queryset
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_serializer(self, *args, **kwargs):
 | 
					    def get_serializer(self, *args, **kwargs):
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
            kwargs['user_detail'] = str2bool(self.request.query_params.get('user_detail', False))
 | 
					            kwargs['user_detail'] = str2bool(self.request.query_params.get('user_detail', False))
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -24,6 +24,7 @@
 | 
				
			|||||||
        {% include "InvenTree/settings/setting.html" with key="ENABLE_PLUGINS_URL" icon="fa-link" %}
 | 
					        {% include "InvenTree/settings/setting.html" with key="ENABLE_PLUGINS_URL" icon="fa-link" %}
 | 
				
			||||||
        {% include "InvenTree/settings/setting.html" with key="ENABLE_PLUGINS_NAVIGATION" icon="fa-sitemap" %}
 | 
					        {% include "InvenTree/settings/setting.html" with key="ENABLE_PLUGINS_NAVIGATION" icon="fa-sitemap" %}
 | 
				
			||||||
        {% include "InvenTree/settings/setting.html" with key="ENABLE_PLUGINS_APP" icon="fa-rocket" %}
 | 
					        {% include "InvenTree/settings/setting.html" with key="ENABLE_PLUGINS_APP" icon="fa-rocket" %}
 | 
				
			||||||
 | 
					        {% include "InvenTree/settings/setting.html" with key="PLUGIN_ON_STARTUP" %}
 | 
				
			||||||
    </tbody>
 | 
					    </tbody>
 | 
				
			||||||
</table>
 | 
					</table>
 | 
				
			||||||
</div>
 | 
					</div>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -34,8 +34,8 @@
 | 
				
			|||||||
// Should the ID be rendered for this string
 | 
					// Should the ID be rendered for this string
 | 
				
			||||||
function renderId(title, pk, parameters={}) {
 | 
					function renderId(title, pk, parameters={}) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Default = true
 | 
					    // Default = do not display
 | 
				
			||||||
    var render = true;
 | 
					    var render = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if ('render_pk' in parameters) {
 | 
					    if ('render_pk' in parameters) {
 | 
				
			||||||
        render = parameters['render_pk'];
 | 
					        render = parameters['render_pk'];
 | 
				
			||||||
@@ -192,7 +192,7 @@ function renderPart(name, data, parameters={}, options={}) {
 | 
				
			|||||||
        <small>
 | 
					        <small>
 | 
				
			||||||
            ${stock_data}
 | 
					            ${stock_data}
 | 
				
			||||||
            ${extra}
 | 
					            ${extra}
 | 
				
			||||||
            ${renderId('{% trans "Part ID" $}', data.pk, parameters)}
 | 
					            ${renderId('{% trans "Part ID" %}', data.pk, parameters)}
 | 
				
			||||||
            </small>
 | 
					            </small>
 | 
				
			||||||
    </span>`;
 | 
					    </span>`;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -373,6 +373,9 @@ function duplicatePart(pk, options={}) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
                // Override the "variant_of" field
 | 
					                // Override the "variant_of" field
 | 
				
			||||||
                data.variant_of = pk;
 | 
					                data.variant_of = pk;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                // By default, disable "is_template" when making a variant *of* a template
 | 
				
			||||||
 | 
					                data.is_template = false;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            
 | 
					            
 | 
				
			||||||
            constructForm('{% url "api-part-list" %}', {
 | 
					            constructForm('{% url "api-part-list" %}', {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1331,14 +1331,27 @@ function loadStockTestResultsTable(table, options) {
 | 
				
			|||||||
            });
 | 
					            });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // Once the test template data are loaded, query for test results
 | 
					            // Once the test template data are loaded, query for test results
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var filters = loadTableFilters(filterKey);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var query_params = {
 | 
				
			||||||
 | 
					                stock_item: options.stock_item,
 | 
				
			||||||
 | 
					                user_detail: true,
 | 
				
			||||||
 | 
					                attachment_detail: true,
 | 
				
			||||||
 | 
					                ordering: '-date',
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if ('result' in filters) {
 | 
				
			||||||
 | 
					                query_params.result = filters.result;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if ('include_installed' in filters) {
 | 
				
			||||||
 | 
					                query_params.include_installed = filters.include_installed;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            inventreeGet(
 | 
					            inventreeGet(
 | 
				
			||||||
                '{% url "api-stock-test-result-list" %}',
 | 
					                '{% url "api-stock-test-result-list" %}',
 | 
				
			||||||
                {
 | 
					                query_params,
 | 
				
			||||||
                    stock_item: options.stock_item,
 | 
					 | 
				
			||||||
                    user_detail: true,
 | 
					 | 
				
			||||||
                    attachment_detail: true,
 | 
					 | 
				
			||||||
                    ordering: '-date',
 | 
					 | 
				
			||||||
                },
 | 
					 | 
				
			||||||
                {
 | 
					                {
 | 
				
			||||||
                    success: function(data) {
 | 
					                    success: function(data) {
 | 
				
			||||||
                        // Iterate through the returned test data
 | 
					                        // Iterate through the returned test data
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -265,7 +265,16 @@ function getAvailableTableFilters(tableKey) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    // Filters for the 'stock test' table
 | 
					    // Filters for the 'stock test' table
 | 
				
			||||||
    if (tableKey == 'stocktests') {
 | 
					    if (tableKey == 'stocktests') {
 | 
				
			||||||
        return {};
 | 
					        return {
 | 
				
			||||||
 | 
					            result: {
 | 
				
			||||||
 | 
					                type: 'bool',
 | 
				
			||||||
 | 
					                title: '{% trans "Test Passed" %}',
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            include_installed: {
 | 
				
			||||||
 | 
					                type: 'bool',
 | 
				
			||||||
 | 
					                title: '{% trans "Include Installed Items" %}',
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Filters for the 'part test template' table
 | 
					    // Filters for the 'part test template' table
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user