diff --git a/InvenTree/InvenTree/status_codes.py b/InvenTree/InvenTree/status_codes.py index c8917d679b..ffe22039c9 100644 --- a/InvenTree/InvenTree/status_codes.py +++ b/InvenTree/InvenTree/status_codes.py @@ -258,6 +258,7 @@ class StockHistoryCode(StatusCode): # Build order codes BUILD_OUTPUT_CREATED = 50 BUILD_OUTPUT_COMPLETED = 55 + BUILD_CONSUMED = 57 # Sales order codes @@ -298,6 +299,7 @@ class StockHistoryCode(StatusCode): BUILD_OUTPUT_CREATED: _('Build order output created'), BUILD_OUTPUT_COMPLETED: _('Build order output completed'), + BUILD_CONSUMED: _('Consumed by build order'), RECEIVED_AGAINST_PURCHASE_ORDER: _('Received against purchase order') diff --git a/InvenTree/InvenTree/version.py b/InvenTree/InvenTree/version.py index bbc022204e..50c07a610e 100644 --- a/InvenTree/InvenTree/version.py +++ b/InvenTree/InvenTree/version.py @@ -9,7 +9,7 @@ import re import common.models # InvenTree software version -INVENTREE_SW_VERSION = "0.6.0" +INVENTREE_SW_VERSION = "0.6.1" # InvenTree API version INVENTREE_API_VERSION = 26 diff --git a/InvenTree/build/models.py b/InvenTree/build/models.py index 74b75787e7..01c2c781e9 100644 --- a/InvenTree/build/models.py +++ b/InvenTree/build/models.py @@ -30,8 +30,6 @@ from InvenTree.helpers import increment, getSetting, normalize, MakeBarcode from InvenTree.models import InvenTreeAttachment, ReferenceIndexingMixin from InvenTree.validators import validate_build_order_reference -import common.models - import InvenTree.fields import InvenTree.helpers import InvenTree.tasks @@ -385,9 +383,7 @@ class Build(MPTTModel, ReferenceIndexingMixin): Returns the BOM items for the part referenced by this BuildOrder """ - return self.part.bom_items.all().prefetch_related( - 'sub_part' - ) + return self.part.get_bom_items() @property def tracked_bom_items(self): @@ -479,8 +475,6 @@ class Build(MPTTModel, ReferenceIndexingMixin): outputs = self.get_build_outputs(complete=True) - # TODO - Ordering? - return outputs @property @@ -491,8 +485,6 @@ class Build(MPTTModel, ReferenceIndexingMixin): outputs = self.get_build_outputs(complete=False) - # TODO - Order by how "complete" they are? - return outputs @property @@ -563,7 +555,7 @@ class Build(MPTTModel, ReferenceIndexingMixin): if self.remaining > 0: return False - if not self.areUntrackedPartsFullyAllocated(): + if not self.are_untracked_parts_allocated(): return False # No issues! @@ -584,7 +576,7 @@ class Build(MPTTModel, ReferenceIndexingMixin): self.save() # Remove untracked allocated stock - self.subtractUntrackedStock(user) + self.subtract_allocated_stock(user) # Ensure that there are no longer any BuildItem objects # which point to thisFcan Build Order @@ -768,7 +760,7 @@ class Build(MPTTModel, ReferenceIndexingMixin): output.delete() @transaction.atomic - def subtractUntrackedStock(self, user): + def subtract_allocated_stock(self, user): """ Called when the Build is marked as "complete", this function removes the allocated untracked items from stock. @@ -831,7 +823,7 @@ class Build(MPTTModel, ReferenceIndexingMixin): self.save() - def requiredQuantity(self, part, output): + def required_quantity(self, bom_item, output=None): """ Get the quantity of a part required to complete the particular build output. @@ -840,12 +832,7 @@ class Build(MPTTModel, ReferenceIndexingMixin): output - The particular build output (StockItem) """ - # Extract the BOM line item from the database - try: - bom_item = PartModels.BomItem.objects.get(part=self.part.pk, sub_part=part.pk) - quantity = bom_item.quantity - except (PartModels.BomItem.DoesNotExist): - quantity = 0 + quantity = bom_item.quantity if output: quantity *= output.quantity @@ -854,32 +841,32 @@ class Build(MPTTModel, ReferenceIndexingMixin): return quantity - def allocatedItems(self, part, output): + def allocated_bom_items(self, bom_item, output=None): """ - Return all BuildItem objects which allocate stock of to + Return all BuildItem objects which allocate stock of to + + Note that the bom_item may allow variants, or direct substitutes, + making things difficult. Args: - part - The part object + bom_item - The BomItem object output - Build output (StockItem). """ - # Remember, if 'variant' stock is allowed to be allocated, it becomes more complicated! - variants = part.get_descendants(include_self=True) - allocations = BuildItem.objects.filter( build=self, - stock_item__part__pk__in=[p.pk for p in variants], + bom_item=bom_item, install_into=output, ) return allocations - def allocatedQuantity(self, part, output): + def allocated_quantity(self, bom_item, output=None): """ Return the total quantity of given part allocated to a given build output. """ - allocations = self.allocatedItems(part, output) + allocations = self.allocated_bom_items(bom_item, output) allocated = allocations.aggregate( q=Coalesce( @@ -891,24 +878,24 @@ class Build(MPTTModel, ReferenceIndexingMixin): return allocated['q'] - def unallocatedQuantity(self, part, output): + def unallocated_quantity(self, bom_item, output=None): """ Return the total unallocated (remaining) quantity of a part against a particular output. """ - required = self.requiredQuantity(part, output) - allocated = self.allocatedQuantity(part, output) + required = self.required_quantity(bom_item, output) + allocated = self.allocated_quantity(bom_item, output) return max(required - allocated, 0) - def isPartFullyAllocated(self, part, output): + def is_bom_item_allocated(self, bom_item, output=None): """ - Returns True if the part has been fully allocated to the particular build output + Test if the supplied BomItem has been fully allocated! """ - return self.unallocatedQuantity(part, output) == 0 + return self.unallocated_quantity(bom_item, output) == 0 - def isFullyAllocated(self, output, verbose=False): + def is_fully_allocated(self, output): """ Returns True if the particular build output is fully allocated. """ @@ -919,53 +906,24 @@ class Build(MPTTModel, ReferenceIndexingMixin): else: bom_items = self.tracked_bom_items - fully_allocated = True - for bom_item in bom_items: - part = bom_item.sub_part - if not self.isPartFullyAllocated(part, output): - fully_allocated = False - - if verbose: - print(f"Part {part} is not fully allocated for output {output}") - else: - break + if not self.is_bom_item_allocated(bom_item, output): + return False # All parts must be fully allocated! - return fully_allocated + return True - def areUntrackedPartsFullyAllocated(self): + def are_untracked_parts_allocated(self): """ Returns True if the un-tracked parts are fully allocated for this BuildOrder """ - return self.isFullyAllocated(None) + return self.is_fully_allocated(None) - def allocatedParts(self, output): + def unallocated_bom_items(self, output): """ - Return a list of parts which have been fully allocated against a particular output - """ - - allocated = [] - - # If output is not specified, we are talking about "untracked" items - if output is None: - bom_items = self.untracked_bom_items - else: - bom_items = self.tracked_bom_items - - for bom_item in bom_items: - part = bom_item.sub_part - - if self.isPartFullyAllocated(part, output): - allocated.append(part) - - return allocated - - def unallocatedParts(self, output): - """ - Return a list of parts which have *not* been fully allocated against a particular output + Return a list of bom items which have *not* been fully allocated against a particular output """ unallocated = [] @@ -977,10 +935,9 @@ class Build(MPTTModel, ReferenceIndexingMixin): bom_items = self.tracked_bom_items for bom_item in bom_items: - part = bom_item.sub_part - if not self.isPartFullyAllocated(part, output): - unallocated.append(part) + if not self.is_bom_item_allocated(bom_item, output): + unallocated.append(bom_item) return unallocated @@ -1008,57 +965,6 @@ class Build(MPTTModel, ReferenceIndexingMixin): return parts - def availableStockItems(self, part, output): - """ - Returns stock items which are available for allocation to this build. - - Args: - part - Part object - output - The particular build output - """ - - # Grab initial query for items which are "in stock" and match the part - items = StockModels.StockItem.objects.filter( - StockModels.StockItem.IN_STOCK_FILTER - ) - - # Check if variants are allowed for this part - try: - bom_item = PartModels.BomItem.objects.get(part=self.part, sub_part=part) - allow_part_variants = bom_item.allow_variants - except PartModels.BomItem.DoesNotExist: - allow_part_variants = False - - if allow_part_variants: - parts = part.get_descendants(include_self=True) - items = items.filter(part__pk__in=[p.pk for p in parts]) - - else: - items = items.filter(part=part) - - # Exclude any items which have already been allocated - allocated = BuildItem.objects.filter( - build=self, - stock_item__part=part, - install_into=output, - ) - - items = items.exclude( - id__in=[item.stock_item.id for item in allocated.all()] - ) - - # Limit query to stock items which are "downstream" of the source location - if self.take_from is not None: - items = items.filter( - location__in=[loc for loc in self.take_from.getUniqueChildren()] - ) - - # Exclude expired stock items - if not common.models.InvenTreeSetting.get_setting('STOCK_ALLOW_EXPIRED_BUILD'): - items = items.exclude(StockModels.StockItem.EXPIRED_FILTER) - - return items - @property def is_active(self): """ Is this build active? An active build is either: @@ -1257,7 +1163,12 @@ class BuildItem(models.Model): if item.part.trackable: # Split the allocated stock if there are more available than allocated if item.quantity > self.quantity: - item = item.splitStock(self.quantity, None, user) + item = item.splitStock( + self.quantity, + None, + user, + code=StockHistoryCode.BUILD_CONSUMED, + ) # Make sure we are pointing to the new item self.stock_item = item @@ -1268,7 +1179,11 @@ class BuildItem(models.Model): item.save() else: # Simply remove the items from stock - item.take_stock(self.quantity, user) + item.take_stock( + self.quantity, + user, + code=StockHistoryCode.BUILD_CONSUMED + ) def getStockItemThumbnail(self): """ diff --git a/InvenTree/build/serializers.py b/InvenTree/build/serializers.py index c7577fa68c..0a8964ee82 100644 --- a/InvenTree/build/serializers.py +++ b/InvenTree/build/serializers.py @@ -160,7 +160,7 @@ class BuildOutputSerializer(serializers.Serializer): if to_complete: # The build output must have all tracked parts allocated - if not build.isFullyAllocated(output): + if not build.is_fully_allocated(output): raise ValidationError(_("This build output is not fully allocated")) return output @@ -236,6 +236,7 @@ class BuildOutputCreateSerializer(serializers.Serializer): auto_allocate = serializers.BooleanField( required=False, default=False, + allow_null=True, label=_('Auto Allocate Serial Numbers'), help_text=_('Automatically allocate required items with matching serial numbers'), ) @@ -403,6 +404,10 @@ class BuildOutputCompleteSerializer(serializers.Serializer): data = self.validated_data + location = data['location'] + status = data['status'] + notes = data.get('notes', '') + outputs = data.get('outputs', []) # Mark the specified build outputs as "complete" @@ -414,8 +419,9 @@ class BuildOutputCompleteSerializer(serializers.Serializer): build.complete_build_output( output, request.user, - status=data['status'], - notes=data.get('notes', '') + location=location, + status=status, + notes=notes, ) @@ -435,7 +441,7 @@ class BuildCompleteSerializer(serializers.Serializer): build = self.context['build'] - if not build.areUntrackedPartsFullyAllocated() and not value: + if not build.are_untracked_parts_allocated() and not value: raise ValidationError(_('Required stock has not been fully allocated')) return value diff --git a/InvenTree/build/templates/build/build_base.html b/InvenTree/build/templates/build/build_base.html index 7340f1486d..cd7126a801 100644 --- a/InvenTree/build/templates/build/build_base.html +++ b/InvenTree/build/templates/build/build_base.html @@ -125,7 +125,7 @@ src="{% static 'img/blank_image.png' %}" {% trans "Required build quantity has not yet been completed" %} {% endif %} - {% if not build.areUntrackedPartsFullyAllocated %} + {% if not build.are_untracked_parts_allocated %}
{% trans "Stock has not been fully allocated to this Build Order" %}
@@ -234,7 +234,7 @@ src="{% static 'img/blank_image.png' %}" {% else %} completeBuildOrder({{ build.pk }}, { - allocated: {% if build.areUntrackedPartsFullyAllocated %}true{% else %}false{% endif %}, + allocated: {% if build.are_untracked_parts_allocated %}true{% else %}false{% endif %}, completed: {% if build.remaining == 0 %}true{% else %}false{% endif %}, }); {% endif %} diff --git a/InvenTree/build/templates/build/detail.html b/InvenTree/build/templates/build/detail.html index 28760c5316..f85ec9afa6 100644 --- a/InvenTree/build/templates/build/detail.html +++ b/InvenTree/build/templates/build/detail.html @@ -192,7 +192,7 @@
{% if build.has_untracked_bom_items %} {% if build.active %} - {% if build.areUntrackedPartsFullyAllocated %} + {% if build.are_untracked_parts_allocated %}
{% trans "Untracked stock has been fully allocated for this Build Order" %}
diff --git a/InvenTree/build/test_build.py b/InvenTree/build/test_build.py index 1a1f0b115e..116c705f61 100644 --- a/InvenTree/build/test_build.py +++ b/InvenTree/build/test_build.py @@ -62,20 +62,20 @@ class BuildTest(TestCase): ) # Create BOM item links for the parts - BomItem.objects.create( + self.bom_item_1 = BomItem.objects.create( part=self.assembly, sub_part=self.sub_part_1, quantity=5 ) - BomItem.objects.create( + self.bom_item_2 = BomItem.objects.create( part=self.assembly, sub_part=self.sub_part_2, quantity=3 ) # sub_part_3 is trackable! - BomItem.objects.create( + self.bom_item_3 = BomItem.objects.create( part=self.assembly, sub_part=self.sub_part_3, quantity=2 @@ -147,15 +147,15 @@ class BuildTest(TestCase): # None of the build outputs have been completed for output in self.build.get_build_outputs().all(): - self.assertFalse(self.build.isFullyAllocated(output)) + self.assertFalse(self.build.is_fully_allocated(output)) - self.assertFalse(self.build.isPartFullyAllocated(self.sub_part_1, self.output_1)) - self.assertFalse(self.build.isPartFullyAllocated(self.sub_part_2, self.output_2)) + self.assertFalse(self.build.is_bom_item_allocated(self.bom_item_1, self.output_1)) + self.assertFalse(self.build.is_bom_item_allocated(self.bom_item_2, self.output_2)) - self.assertEqual(self.build.unallocatedQuantity(self.sub_part_1, self.output_1), 15) - self.assertEqual(self.build.unallocatedQuantity(self.sub_part_1, self.output_2), 35) - self.assertEqual(self.build.unallocatedQuantity(self.sub_part_2, self.output_1), 9) - self.assertEqual(self.build.unallocatedQuantity(self.sub_part_2, self.output_2), 21) + self.assertEqual(self.build.unallocated_quantity(self.bom_item_1, self.output_1), 15) + self.assertEqual(self.build.unallocated_quantity(self.bom_item_1, self.output_2), 35) + self.assertEqual(self.build.unallocated_quantity(self.bom_item_2, self.output_1), 9) + self.assertEqual(self.build.unallocated_quantity(self.bom_item_2, self.output_2), 21) self.assertFalse(self.build.is_complete) @@ -226,7 +226,7 @@ class BuildTest(TestCase): } ) - self.assertTrue(self.build.isFullyAllocated(self.output_1)) + self.assertTrue(self.build.is_fully_allocated(self.output_1)) # Partially allocate tracked stock against build output 2 self.allocate_stock( @@ -236,7 +236,7 @@ class BuildTest(TestCase): } ) - self.assertFalse(self.build.isFullyAllocated(self.output_2)) + self.assertFalse(self.build.is_fully_allocated(self.output_2)) # Partially allocate untracked stock against build self.allocate_stock( @@ -247,9 +247,9 @@ class BuildTest(TestCase): } ) - self.assertFalse(self.build.isFullyAllocated(None, verbose=True)) + self.assertFalse(self.build.is_fully_allocated(None)) - unallocated = self.build.unallocatedParts(None) + unallocated = self.build.unallocated_bom_items(None) self.assertEqual(len(unallocated), 2) @@ -260,19 +260,19 @@ class BuildTest(TestCase): } ) - self.assertFalse(self.build.isFullyAllocated(None, verbose=True)) + self.assertFalse(self.build.is_fully_allocated(None)) - unallocated = self.build.unallocatedParts(None) + unallocated = self.build.unallocated_bom_items(None) self.assertEqual(len(unallocated), 1) self.build.unallocateStock() - unallocated = self.build.unallocatedParts(None) + unallocated = self.build.unallocated_bom_items(None) self.assertEqual(len(unallocated), 2) - self.assertFalse(self.build.areUntrackedPartsFullyAllocated()) + self.assertFalse(self.build.are_untracked_parts_allocated()) # Now we "fully" allocate the untracked untracked items self.allocate_stock( @@ -283,7 +283,7 @@ class BuildTest(TestCase): } ) - self.assertTrue(self.build.areUntrackedPartsFullyAllocated()) + self.assertTrue(self.build.are_untracked_parts_allocated()) def test_cancel(self): """ @@ -331,9 +331,9 @@ class BuildTest(TestCase): } ) - self.assertTrue(self.build.isFullyAllocated(None, verbose=True)) - self.assertTrue(self.build.isFullyAllocated(self.output_1)) - self.assertTrue(self.build.isFullyAllocated(self.output_2)) + self.assertTrue(self.build.is_fully_allocated(None)) + self.assertTrue(self.build.is_fully_allocated(self.output_1)) + self.assertTrue(self.build.is_fully_allocated(self.output_2)) self.build.complete_build_output(self.output_1, None) diff --git a/InvenTree/part/migrations/0056_auto_20201110_1125.py b/InvenTree/part/migrations/0056_auto_20201110_1125.py index e78482db76..efb36b1812 100644 --- a/InvenTree/part/migrations/0056_auto_20201110_1125.py +++ b/InvenTree/part/migrations/0056_auto_20201110_1125.py @@ -1,5 +1,7 @@ # Generated by Django 3.0.7 on 2020-11-10 11:25 +import logging + from django.db import migrations from moneyed import CURRENCIES @@ -7,6 +9,9 @@ from django.db import migrations, connection from company.models import SupplierPriceBreak +logger = logging.getLogger('inventree') + + def migrate_currencies(apps, schema_editor): """ Migrate from the 'old' method of handling currencies, @@ -19,7 +24,7 @@ def migrate_currencies(apps, schema_editor): for the SupplierPriceBreak model, to a new django-money compatible currency. """ - print("Updating currency references for SupplierPriceBreak model...") + logger.info("Updating currency references for SupplierPriceBreak model...") # A list of available currency codes currency_codes = CURRENCIES.keys() diff --git a/InvenTree/part/models.py b/InvenTree/part/models.py index 33ad8bf612..09e1f77542 100644 --- a/InvenTree/part/models.py +++ b/InvenTree/part/models.py @@ -1453,7 +1453,9 @@ class Part(MPTTModel): By default, will include inherited BOM items """ - return BomItem.objects.filter(self.get_bom_item_filter(include_inherited=include_inherited)) + queryset = BomItem.objects.filter(self.get_bom_item_filter(include_inherited=include_inherited)) + + return queryset.prefetch_related('sub_part') def get_installed_part_options(self, include_inherited=True, include_variants=True): """ diff --git a/InvenTree/part/templates/part/detail.html b/InvenTree/part/templates/part/detail.html index 2266b39048..5b92a3af01 100644 --- a/InvenTree/part/templates/part/detail.html +++ b/InvenTree/part/templates/part/detail.html @@ -122,7 +122,13 @@

{% trans "Sales Order Allocations" %}

-
+ +
+
+ {% include "filter_list.html" with id="salesorderallocation" %} +
+
+
@@ -342,7 +348,12 @@

{% trans "Build Order Allocations" %}

-
+
+
+ {% include "filter_list.html" with id="buildorderallocation" %} +
+
+
@@ -722,6 +733,7 @@ }); // Load the BOM table data in the pricing view + {% if part.has_bom and roles.sales_order.view %} loadBomTable($("#bom-pricing-table"), { editable: false, bom_url: "{% url 'api-bom-list' %}", @@ -729,6 +741,7 @@ parent_id: {{ part.id }} , sub_part_detail: true, }); + {% endif %} onPanelLoad("purchase-orders", function() { loadPartPurchaseOrderTable( diff --git a/InvenTree/part/templates/part/part_base.html b/InvenTree/part/templates/part/part_base.html index d2505a57f7..67baaf0636 100644 --- a/InvenTree/part/templates/part/part_base.html +++ b/InvenTree/part/templates/part/part_base.html @@ -59,13 +59,13 @@ - - -{% setting_object 'STOCK_OWNERSHIP_CONTROL' as owner_control %} -{% if owner_control.value == "True" %} - {% authorized_owners item.owner as owners %} -{% endif %} - -{% if owner_control.value == "False" or owner_control.value == "True" and user in owners or user.is_superuser %} +{% if user_owns_item %} {% if roles.stock.change and not item.is_building %}
-{% if owner_control.value == "False" or owner_control.value == "True" and user in owners or user.is_superuser %} +{% if user_owns_location %} {% if roles.stock.change %}
{% endif %} -{% endif %} {% endblock %} {% block details_left %} @@ -106,23 +105,23 @@ {% trans "Top level stock location" %} {% endif %} + {% if ownership_enabled and location_owner %} + + + {% trans "Location Owner" %} + + {{ location_owner }} + {% if not user_owns_location %} + + {% trans "Read only" %} + + {% endif %} + + + {% endif %} {% endblock details_left %} -{% block details_below %} -{% setting_object 'STOCK_OWNERSHIP_CONTROL' as owner_control %} -{% if owner_control.value == "True" %} - {% authorized_owners location.owner as owners %} - - {% if location and not user in owners and not user.is_superuser %} -
- {% trans "You are not in the list of owners of this location. This stock location cannot be edited." %}
-
- {% endif %} -{% endif %} - -{% endblock details_below %} - {% block details_right %} {% if location %} diff --git a/InvenTree/stock/views.py b/InvenTree/stock/views.py index 9aa70255b1..d1fde25b0a 100644 --- a/InvenTree/stock/views.py +++ b/InvenTree/stock/views.py @@ -63,6 +63,11 @@ class StockIndex(InvenTreeRoleMixin, ListView): context['loc_count'] = StockLocation.objects.count() context['stock_count'] = StockItem.objects.count() + # No 'ownership' checks are necessary for the top-level StockLocation view + context['user_owns_location'] = True + context['location_owner'] = None + context['ownership_enabled'] = common.models.InvenTreeSetting.get_setting('STOCK_OWNERSHIP_CONTROL') + return context @@ -76,6 +81,16 @@ class StockLocationDetail(InvenTreeRoleMixin, DetailView): queryset = StockLocation.objects.all() model = StockLocation + def get_context_data(self, **kwargs): + + context = super().get_context_data(**kwargs) + + context['ownership_enabled'] = common.models.InvenTreeSetting.get_setting('STOCK_OWNERSHIP_CONTROL') + context['location_owner'] = context['location'].get_location_owner() + context['user_owns_location'] = context['location'].check_ownership(self.request.user) + + return context + class StockItemDetail(InvenTreeRoleMixin, DetailView): """ @@ -126,6 +141,10 @@ class StockItemDetail(InvenTreeRoleMixin, DetailView): # We only support integer serial number progression pass + data['ownership_enabled'] = common.models.InvenTreeSetting.get_setting('STOCK_OWNERSHIP_CONTROL') + data['item_owner'] = self.object.get_item_owner() + data['user_owns_item'] = self.object.check_ownership(self.request.user) + return data def get(self, request, *args, **kwargs): diff --git a/InvenTree/templates/js/translated/stock.js b/InvenTree/templates/js/translated/stock.js index 10b1b71073..2d84f11e4a 100644 --- a/InvenTree/templates/js/translated/stock.js +++ b/InvenTree/templates/js/translated/stock.js @@ -1554,11 +1554,11 @@ function locationDetail(row, showLink=true) { } else if (row.belongs_to) { // StockItem is installed inside a different StockItem text = `{% trans "Installed in Stock Item" %} ${row.belongs_to}`; - url = `/stock/item/${row.belongs_to}/installed/`; + url = `/stock/item/${row.belongs_to}/?display=installed-items`; } else if (row.customer) { // StockItem has been assigned to a customer text = '{% trans "Shipped to customer" %}'; - url = `/company/${row.customer}/assigned-stock/`; + url = `/company/${row.customer}/?display=assigned-stock`; } else if (row.sales_order) { // StockItem has been assigned to a sales order text = '{% trans "Assigned to Sales Order" %}'; diff --git a/InvenTree/templates/js/translated/tables.js b/InvenTree/templates/js/translated/tables.js index 4c9bec0476..c2418dbe78 100644 --- a/InvenTree/templates/js/translated/tables.js +++ b/InvenTree/templates/js/translated/tables.js @@ -278,7 +278,7 @@ $.fn.inventreeTable = function(options) { } }); } else { - console.log(`Could not get list of visible columns for column '${tableName}'`); + console.log(`Could not get list of visible columns for table '${tableName}'`); } } diff --git a/InvenTree/templates/stock_table.html b/InvenTree/templates/stock_table.html index 4a20938869..a8a4ec6691 100644 --- a/InvenTree/templates/stock_table.html +++ b/InvenTree/templates/stock_table.html @@ -46,16 +46,16 @@ diff --git a/InvenTree/users/models.py b/InvenTree/users/models.py index a95fd21385..c593fb49f3 100644 --- a/InvenTree/users/models.py +++ b/InvenTree/users/models.py @@ -451,7 +451,7 @@ def update_group_roles(group, debug=False): group.permissions.add(permission) if debug: # pragma: no cover - print(f"Adding permission {perm} to group {group.name}") + logger.info(f"Adding permission {perm} to group {group.name}") # Remove any extra permissions from the group for perm in permissions_to_delete: @@ -466,7 +466,7 @@ def update_group_roles(group, debug=False): group.permissions.remove(permission) if debug: # pragma: no cover - print(f"Removing permission {perm} from group {group.name}") + logger.info(f"Removing permission {perm} from group {group.name}") # Enable all action permissions for certain children models # if parent model has 'change' permission @@ -488,7 +488,7 @@ def update_group_roles(group, debug=False): permission = get_permission_object(child_perm) if permission: group.permissions.add(permission) - print(f"Adding permission {child_perm} to group {group.name}") + logger.info(f"Adding permission {child_perm} to group {group.name}") @receiver(post_save, sender=Group, dispatch_uid='create_missing_rule_sets')