Merge branch 'inventree:master' into matmair/issue2279

This commit is contained in:
Matthias Mair 2022-02-28 00:45:58 +01:00 committed by GitHub
commit 86ba69eeaf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
35 changed files with 3473 additions and 3366 deletions

View File

@ -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')

View File

@ -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
@ -479,8 +477,6 @@ class Build(MPTTModel, ReferenceIndexingMixin):
outputs = self.get_build_outputs(complete=True)
# TODO - Ordering?
return outputs
@property
@ -491,8 +487,6 @@ class Build(MPTTModel, ReferenceIndexingMixin):
outputs = self.get_build_outputs(complete=False)
# TODO - Order by how "complete" they are?
return outputs
@property
@ -563,7 +557,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 +578,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 +762,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 +825,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 +834,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 +843,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 <part> to <output>
Return all BuildItem objects which allocate stock of <bom_item> to <output>
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 +880,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 +908,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 +937,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 +967,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 +1165,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 +1181,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):
"""

View File

@ -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

View File

@ -125,7 +125,7 @@ src="{% static 'img/blank_image.png' %}"
{% trans "Required build quantity has not yet been completed" %}
</div>
{% endif %}
{% if not build.areUntrackedPartsFullyAllocated %}
{% if not build.are_untracked_parts_allocated %}
<div class='alert alert-block alert-warning'>
{% trans "Stock has not been fully allocated to this Build Order" %}
</div>
@ -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 %}

View File

@ -192,7 +192,7 @@
<div class='panel-content'>
{% if build.has_untracked_bom_items %}
{% if build.active %}
{% if build.areUntrackedPartsFullyAllocated %}
{% if build.are_untracked_parts_allocated %}
<div class='alert alert-block alert-success'>
{% trans "Untracked stock has been fully allocated for this Build Order" %}
</div>

View File

@ -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)

View File

@ -3,8 +3,8 @@ msgid ""
msgstr ""
"Project-Id-Version: inventree\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-02-20 22:01+0000\n"
"PO-Revision-Date: 2022-02-20 23:03\n"
"POT-Creation-Date: 2022-02-22 01:07+0000\n"
"PO-Revision-Date: 2022-02-22 11:36\n"
"Last-Translator: \n"
"Language-Team: German\n"
"Language: de_DE\n"
@ -328,54 +328,58 @@ msgid "Hebrew"
msgstr "Hebräisch"
#: InvenTree/settings.py:662
msgid "Hungarian"
msgstr "Ungarisch"
#: InvenTree/settings.py:663
msgid "Italian"
msgstr "Italienisch"
#: InvenTree/settings.py:663
#: InvenTree/settings.py:664
msgid "Japanese"
msgstr "Japanisch"
#: InvenTree/settings.py:664
#: InvenTree/settings.py:665
msgid "Korean"
msgstr "Koreanisch"
#: InvenTree/settings.py:665
#: InvenTree/settings.py:666
msgid "Dutch"
msgstr "Niederländisch"
#: InvenTree/settings.py:666
#: InvenTree/settings.py:667
msgid "Norwegian"
msgstr "Norwegisch"
#: InvenTree/settings.py:667
#: InvenTree/settings.py:668
msgid "Polish"
msgstr "Polnisch"
#: InvenTree/settings.py:668
#: InvenTree/settings.py:669
msgid "Portugese"
msgstr "Portugiesisch"
#: InvenTree/settings.py:669
#: InvenTree/settings.py:670
msgid "Russian"
msgstr "Russisch"
#: InvenTree/settings.py:670
#: InvenTree/settings.py:671
msgid "Swedish"
msgstr "Schwedisch"
#: InvenTree/settings.py:671
#: InvenTree/settings.py:672
msgid "Thai"
msgstr "Thailändisch"
#: InvenTree/settings.py:672
#: InvenTree/settings.py:673
msgid "Turkish"
msgstr "Türkisch"
#: InvenTree/settings.py:673
#: InvenTree/settings.py:674
msgid "Vietnamese"
msgstr "Vietnamesisch"
#: InvenTree/settings.py:674
#: InvenTree/settings.py:675
msgid "Chinese"
msgstr "Chinesisch"

View File

@ -3,8 +3,8 @@ msgid ""
msgstr ""
"Project-Id-Version: inventree\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-02-20 22:01+0000\n"
"PO-Revision-Date: 2022-02-20 22:02\n"
"POT-Creation-Date: 2022-02-22 01:07+0000\n"
"PO-Revision-Date: 2022-02-22 01:18\n"
"Last-Translator: \n"
"Language-Team: Greek\n"
"Language: el_GR\n"
@ -328,54 +328,58 @@ msgid "Hebrew"
msgstr ""
#: InvenTree/settings.py:662
msgid "Italian"
msgid "Hungarian"
msgstr ""
#: InvenTree/settings.py:663
msgid "Japanese"
msgid "Italian"
msgstr ""
#: InvenTree/settings.py:664
msgid "Korean"
msgid "Japanese"
msgstr ""
#: InvenTree/settings.py:665
msgid "Dutch"
msgid "Korean"
msgstr ""
#: InvenTree/settings.py:666
msgid "Norwegian"
msgid "Dutch"
msgstr ""
#: InvenTree/settings.py:667
msgid "Polish"
msgid "Norwegian"
msgstr ""
#: InvenTree/settings.py:668
msgid "Portugese"
msgid "Polish"
msgstr ""
#: InvenTree/settings.py:669
msgid "Russian"
msgid "Portugese"
msgstr ""
#: InvenTree/settings.py:670
msgid "Swedish"
msgid "Russian"
msgstr ""
#: InvenTree/settings.py:671
msgid "Thai"
msgid "Swedish"
msgstr ""
#: InvenTree/settings.py:672
msgid "Turkish"
msgid "Thai"
msgstr ""
#: InvenTree/settings.py:673
msgid "Vietnamese"
msgid "Turkish"
msgstr ""
#: InvenTree/settings.py:674
msgid "Vietnamese"
msgstr ""
#: InvenTree/settings.py:675
msgid "Chinese"
msgstr ""

File diff suppressed because it is too large Load Diff

View File

@ -3,8 +3,8 @@ msgid ""
msgstr ""
"Project-Id-Version: inventree\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-02-20 22:01+0000\n"
"PO-Revision-Date: 2022-02-20 22:02\n"
"POT-Creation-Date: 2022-02-22 01:07+0000\n"
"PO-Revision-Date: 2022-02-22 01:18\n"
"Last-Translator: \n"
"Language-Team: French\n"
"Language: fr_FR\n"
@ -328,54 +328,58 @@ msgid "Hebrew"
msgstr "Hebrew"
#: InvenTree/settings.py:662
msgid "Hungarian"
msgstr ""
#: InvenTree/settings.py:663
msgid "Italian"
msgstr "Italian"
#: InvenTree/settings.py:663
#: InvenTree/settings.py:664
msgid "Japanese"
msgstr "Japanese"
#: InvenTree/settings.py:664
#: InvenTree/settings.py:665
msgid "Korean"
msgstr "Korean"
#: InvenTree/settings.py:665
#: InvenTree/settings.py:666
msgid "Dutch"
msgstr "Dutch"
#: InvenTree/settings.py:666
#: InvenTree/settings.py:667
msgid "Norwegian"
msgstr "Norwegian"
#: InvenTree/settings.py:667
#: InvenTree/settings.py:668
msgid "Polish"
msgstr "Polonais"
#: InvenTree/settings.py:668
#: InvenTree/settings.py:669
msgid "Portugese"
msgstr "Portugais"
#: InvenTree/settings.py:669
#: InvenTree/settings.py:670
msgid "Russian"
msgstr "Russian"
#: InvenTree/settings.py:670
#: InvenTree/settings.py:671
msgid "Swedish"
msgstr "Swedish"
#: InvenTree/settings.py:671
#: InvenTree/settings.py:672
msgid "Thai"
msgstr "Thai"
#: InvenTree/settings.py:672
#: InvenTree/settings.py:673
msgid "Turkish"
msgstr "Turc"
#: InvenTree/settings.py:673
#: InvenTree/settings.py:674
msgid "Vietnamese"
msgstr "Vietnamese"
#: InvenTree/settings.py:674
#: InvenTree/settings.py:675
msgid "Chinese"
msgstr "Chinese"

View File

@ -3,8 +3,8 @@ msgid ""
msgstr ""
"Project-Id-Version: inventree\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-02-20 22:01+0000\n"
"PO-Revision-Date: 2022-02-20 22:02\n"
"POT-Creation-Date: 2022-02-22 01:07+0000\n"
"PO-Revision-Date: 2022-02-22 01:18\n"
"Last-Translator: \n"
"Language-Team: Hebrew\n"
"Language: he_IL\n"
@ -328,54 +328,58 @@ msgid "Hebrew"
msgstr "עברית"
#: InvenTree/settings.py:662
msgid "Hungarian"
msgstr ""
#: InvenTree/settings.py:663
msgid "Italian"
msgstr "איטלקית"
#: InvenTree/settings.py:663
#: InvenTree/settings.py:664
msgid "Japanese"
msgstr "יפנית"
#: InvenTree/settings.py:664
#: InvenTree/settings.py:665
msgid "Korean"
msgstr "קוריאנית"
#: InvenTree/settings.py:665
#: InvenTree/settings.py:666
msgid "Dutch"
msgstr "הולנדית"
#: InvenTree/settings.py:666
#: InvenTree/settings.py:667
msgid "Norwegian"
msgstr "נורווגית"
#: InvenTree/settings.py:667
#: InvenTree/settings.py:668
msgid "Polish"
msgstr "פולנית"
#: InvenTree/settings.py:668
#: InvenTree/settings.py:669
msgid "Portugese"
msgstr "פורטוגזית"
#: InvenTree/settings.py:669
#: InvenTree/settings.py:670
msgid "Russian"
msgstr "רוסית"
#: InvenTree/settings.py:670
#: InvenTree/settings.py:671
msgid "Swedish"
msgstr "שוודית"
#: InvenTree/settings.py:671
#: InvenTree/settings.py:672
msgid "Thai"
msgstr "תאילנדית"
#: InvenTree/settings.py:672
#: InvenTree/settings.py:673
msgid "Turkish"
msgstr "טורקית"
#: InvenTree/settings.py:673
#: InvenTree/settings.py:674
msgid "Vietnamese"
msgstr "ווייטנאמית"
#: InvenTree/settings.py:674
#: InvenTree/settings.py:675
msgid "Chinese"
msgstr "סינית"

File diff suppressed because it is too large Load Diff

View File

@ -3,8 +3,8 @@ msgid ""
msgstr ""
"Project-Id-Version: inventree\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-02-20 22:01+0000\n"
"PO-Revision-Date: 2022-02-20 22:02\n"
"POT-Creation-Date: 2022-02-22 01:07+0000\n"
"PO-Revision-Date: 2022-02-22 01:18\n"
"Last-Translator: \n"
"Language-Team: Indonesian\n"
"Language: id_ID\n"
@ -328,54 +328,58 @@ msgid "Hebrew"
msgstr ""
#: InvenTree/settings.py:662
msgid "Italian"
msgid "Hungarian"
msgstr ""
#: InvenTree/settings.py:663
msgid "Japanese"
msgid "Italian"
msgstr ""
#: InvenTree/settings.py:664
msgid "Korean"
msgid "Japanese"
msgstr ""
#: InvenTree/settings.py:665
msgid "Dutch"
msgid "Korean"
msgstr ""
#: InvenTree/settings.py:666
msgid "Norwegian"
msgid "Dutch"
msgstr ""
#: InvenTree/settings.py:667
msgid "Polish"
msgid "Norwegian"
msgstr ""
#: InvenTree/settings.py:668
msgid "Portugese"
msgid "Polish"
msgstr ""
#: InvenTree/settings.py:669
msgid "Russian"
msgid "Portugese"
msgstr ""
#: InvenTree/settings.py:670
msgid "Swedish"
msgid "Russian"
msgstr ""
#: InvenTree/settings.py:671
msgid "Thai"
msgid "Swedish"
msgstr ""
#: InvenTree/settings.py:672
msgid "Turkish"
msgid "Thai"
msgstr ""
#: InvenTree/settings.py:673
msgid "Vietnamese"
msgid "Turkish"
msgstr ""
#: InvenTree/settings.py:674
msgid "Vietnamese"
msgstr ""
#: InvenTree/settings.py:675
msgid "Chinese"
msgstr ""

View File

@ -3,8 +3,8 @@ msgid ""
msgstr ""
"Project-Id-Version: inventree\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-02-20 22:01+0000\n"
"PO-Revision-Date: 2022-02-20 22:03\n"
"POT-Creation-Date: 2022-02-22 01:07+0000\n"
"PO-Revision-Date: 2022-02-22 01:18\n"
"Last-Translator: \n"
"Language-Team: Italian\n"
"Language: it_IT\n"
@ -328,54 +328,58 @@ msgid "Hebrew"
msgstr "Ebraico"
#: InvenTree/settings.py:662
msgid "Hungarian"
msgstr ""
#: InvenTree/settings.py:663
msgid "Italian"
msgstr "Italiano"
#: InvenTree/settings.py:663
#: InvenTree/settings.py:664
msgid "Japanese"
msgstr "Giapponese"
#: InvenTree/settings.py:664
#: InvenTree/settings.py:665
msgid "Korean"
msgstr "Coreano"
#: InvenTree/settings.py:665
#: InvenTree/settings.py:666
msgid "Dutch"
msgstr "Olandese"
#: InvenTree/settings.py:666
#: InvenTree/settings.py:667
msgid "Norwegian"
msgstr "Norvegese"
#: InvenTree/settings.py:667
#: InvenTree/settings.py:668
msgid "Polish"
msgstr "Polacco"
#: InvenTree/settings.py:668
#: InvenTree/settings.py:669
msgid "Portugese"
msgstr "Portoghese"
#: InvenTree/settings.py:669
#: InvenTree/settings.py:670
msgid "Russian"
msgstr "Russo"
#: InvenTree/settings.py:670
#: InvenTree/settings.py:671
msgid "Swedish"
msgstr "Svedese"
#: InvenTree/settings.py:671
#: InvenTree/settings.py:672
msgid "Thai"
msgstr "Thailandese"
#: InvenTree/settings.py:672
#: InvenTree/settings.py:673
msgid "Turkish"
msgstr "Turco"
#: InvenTree/settings.py:673
#: InvenTree/settings.py:674
msgid "Vietnamese"
msgstr "Vietnamita"
#: InvenTree/settings.py:674
#: InvenTree/settings.py:675
msgid "Chinese"
msgstr "Cinese"

View File

@ -3,8 +3,8 @@ msgid ""
msgstr ""
"Project-Id-Version: inventree\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-02-20 22:01+0000\n"
"PO-Revision-Date: 2022-02-20 22:03\n"
"POT-Creation-Date: 2022-02-22 01:07+0000\n"
"PO-Revision-Date: 2022-02-22 01:18\n"
"Last-Translator: \n"
"Language-Team: Japanese\n"
"Language: ja_JP\n"
@ -328,54 +328,58 @@ msgid "Hebrew"
msgstr ""
#: InvenTree/settings.py:662
msgid "Italian"
msgid "Hungarian"
msgstr ""
#: InvenTree/settings.py:663
msgid "Japanese"
msgid "Italian"
msgstr ""
#: InvenTree/settings.py:664
msgid "Korean"
msgid "Japanese"
msgstr ""
#: InvenTree/settings.py:665
msgid "Dutch"
msgid "Korean"
msgstr ""
#: InvenTree/settings.py:666
msgid "Norwegian"
msgid "Dutch"
msgstr ""
#: InvenTree/settings.py:667
msgid "Norwegian"
msgstr ""
#: InvenTree/settings.py:668
msgid "Polish"
msgstr "ポーランド語"
#: InvenTree/settings.py:668
#: InvenTree/settings.py:669
msgid "Portugese"
msgstr ""
#: InvenTree/settings.py:669
#: InvenTree/settings.py:670
msgid "Russian"
msgstr ""
#: InvenTree/settings.py:670
#: InvenTree/settings.py:671
msgid "Swedish"
msgstr ""
#: InvenTree/settings.py:671
#: InvenTree/settings.py:672
msgid "Thai"
msgstr ""
#: InvenTree/settings.py:672
#: InvenTree/settings.py:673
msgid "Turkish"
msgstr "トルコ語"
#: InvenTree/settings.py:673
#: InvenTree/settings.py:674
msgid "Vietnamese"
msgstr ""
#: InvenTree/settings.py:674
#: InvenTree/settings.py:675
msgid "Chinese"
msgstr ""

View File

@ -3,8 +3,8 @@ msgid ""
msgstr ""
"Project-Id-Version: inventree\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-02-20 22:01+0000\n"
"PO-Revision-Date: 2022-02-20 22:02\n"
"POT-Creation-Date: 2022-02-22 01:07+0000\n"
"PO-Revision-Date: 2022-02-22 01:18\n"
"Last-Translator: \n"
"Language-Team: Korean\n"
"Language: ko_KR\n"
@ -328,54 +328,58 @@ msgid "Hebrew"
msgstr "히브리어"
#: InvenTree/settings.py:662
msgid "Hungarian"
msgstr ""
#: InvenTree/settings.py:663
msgid "Italian"
msgstr "이탈리아어"
#: InvenTree/settings.py:663
#: InvenTree/settings.py:664
msgid "Japanese"
msgstr "일본어"
#: InvenTree/settings.py:664
#: InvenTree/settings.py:665
msgid "Korean"
msgstr "한국어"
#: InvenTree/settings.py:665
#: InvenTree/settings.py:666
msgid "Dutch"
msgstr "네덜란드어"
#: InvenTree/settings.py:666
#: InvenTree/settings.py:667
msgid "Norwegian"
msgstr "노르웨이어"
#: InvenTree/settings.py:667
#: InvenTree/settings.py:668
msgid "Polish"
msgstr "폴란드어"
#: InvenTree/settings.py:668
#: InvenTree/settings.py:669
msgid "Portugese"
msgstr "포르투갈어"
#: InvenTree/settings.py:669
#: InvenTree/settings.py:670
msgid "Russian"
msgstr "러시아어"
#: InvenTree/settings.py:670
#: InvenTree/settings.py:671
msgid "Swedish"
msgstr "스웨덴어"
#: InvenTree/settings.py:671
#: InvenTree/settings.py:672
msgid "Thai"
msgstr "태국어"
#: InvenTree/settings.py:672
#: InvenTree/settings.py:673
msgid "Turkish"
msgstr "터키어"
#: InvenTree/settings.py:673
#: InvenTree/settings.py:674
msgid "Vietnamese"
msgstr "베트남어"
#: InvenTree/settings.py:674
#: InvenTree/settings.py:675
msgid "Chinese"
msgstr "중국어"

View File

@ -3,8 +3,8 @@ msgid ""
msgstr ""
"Project-Id-Version: inventree\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-02-20 22:01+0000\n"
"PO-Revision-Date: 2022-02-20 22:02\n"
"POT-Creation-Date: 2022-02-22 01:07+0000\n"
"PO-Revision-Date: 2022-02-22 01:18\n"
"Last-Translator: \n"
"Language-Team: Dutch\n"
"Language: nl_NL\n"
@ -328,54 +328,58 @@ msgid "Hebrew"
msgstr "Hebreeuws"
#: InvenTree/settings.py:662
msgid "Hungarian"
msgstr ""
#: InvenTree/settings.py:663
msgid "Italian"
msgstr "Italiaans"
#: InvenTree/settings.py:663
#: InvenTree/settings.py:664
msgid "Japanese"
msgstr "Japans"
#: InvenTree/settings.py:664
#: InvenTree/settings.py:665
msgid "Korean"
msgstr "Koreaans"
#: InvenTree/settings.py:665
#: InvenTree/settings.py:666
msgid "Dutch"
msgstr "Nederlands"
#: InvenTree/settings.py:666
#: InvenTree/settings.py:667
msgid "Norwegian"
msgstr "Noors"
#: InvenTree/settings.py:667
#: InvenTree/settings.py:668
msgid "Polish"
msgstr "Pools"
#: InvenTree/settings.py:668
#: InvenTree/settings.py:669
msgid "Portugese"
msgstr "Portugees"
#: InvenTree/settings.py:669
#: InvenTree/settings.py:670
msgid "Russian"
msgstr "Russisch"
#: InvenTree/settings.py:670
#: InvenTree/settings.py:671
msgid "Swedish"
msgstr "Zweeds"
#: InvenTree/settings.py:671
#: InvenTree/settings.py:672
msgid "Thai"
msgstr "Thais"
#: InvenTree/settings.py:672
#: InvenTree/settings.py:673
msgid "Turkish"
msgstr "Turks"
#: InvenTree/settings.py:673
#: InvenTree/settings.py:674
msgid "Vietnamese"
msgstr "Vietnamees"
#: InvenTree/settings.py:674
#: InvenTree/settings.py:675
msgid "Chinese"
msgstr "Chinees"

View File

@ -3,8 +3,8 @@ msgid ""
msgstr ""
"Project-Id-Version: inventree\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-02-20 22:01+0000\n"
"PO-Revision-Date: 2022-02-20 22:02\n"
"POT-Creation-Date: 2022-02-22 01:07+0000\n"
"PO-Revision-Date: 2022-02-22 01:18\n"
"Last-Translator: \n"
"Language-Team: Norwegian\n"
"Language: no_NO\n"
@ -328,54 +328,58 @@ msgid "Hebrew"
msgstr "Hebraisk"
#: InvenTree/settings.py:662
msgid "Hungarian"
msgstr ""
#: InvenTree/settings.py:663
msgid "Italian"
msgstr "Italiensk"
#: InvenTree/settings.py:663
#: InvenTree/settings.py:664
msgid "Japanese"
msgstr "Japansk"
#: InvenTree/settings.py:664
#: InvenTree/settings.py:665
msgid "Korean"
msgstr "Koreansk"
#: InvenTree/settings.py:665
#: InvenTree/settings.py:666
msgid "Dutch"
msgstr "Nederlandsk"
#: InvenTree/settings.py:666
#: InvenTree/settings.py:667
msgid "Norwegian"
msgstr "Norsk"
#: InvenTree/settings.py:667
#: InvenTree/settings.py:668
msgid "Polish"
msgstr "Polsk"
#: InvenTree/settings.py:668
#: InvenTree/settings.py:669
msgid "Portugese"
msgstr "Portugesisk"
#: InvenTree/settings.py:669
#: InvenTree/settings.py:670
msgid "Russian"
msgstr "Russisk"
#: InvenTree/settings.py:670
#: InvenTree/settings.py:671
msgid "Swedish"
msgstr "Svensk"
#: InvenTree/settings.py:671
#: InvenTree/settings.py:672
msgid "Thai"
msgstr "Thailandsk"
#: InvenTree/settings.py:672
#: InvenTree/settings.py:673
msgid "Turkish"
msgstr "Tyrkisk"
#: InvenTree/settings.py:673
#: InvenTree/settings.py:674
msgid "Vietnamese"
msgstr "Vietnamesisk"
#: InvenTree/settings.py:674
#: InvenTree/settings.py:675
msgid "Chinese"
msgstr "Kinesisk"

View File

@ -3,8 +3,8 @@ msgid ""
msgstr ""
"Project-Id-Version: inventree\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-02-20 22:01+0000\n"
"PO-Revision-Date: 2022-02-20 22:03\n"
"POT-Creation-Date: 2022-02-22 01:07+0000\n"
"PO-Revision-Date: 2022-02-22 01:18\n"
"Last-Translator: \n"
"Language-Team: Polish\n"
"Language: pl_PL\n"
@ -328,54 +328,58 @@ msgid "Hebrew"
msgstr "Hebrajski"
#: InvenTree/settings.py:662
msgid "Hungarian"
msgstr ""
#: InvenTree/settings.py:663
msgid "Italian"
msgstr "Włoski"
#: InvenTree/settings.py:663
#: InvenTree/settings.py:664
msgid "Japanese"
msgstr "Japoński"
#: InvenTree/settings.py:664
#: InvenTree/settings.py:665
msgid "Korean"
msgstr "Koreański"
#: InvenTree/settings.py:665
#: InvenTree/settings.py:666
msgid "Dutch"
msgstr "Holenderski"
#: InvenTree/settings.py:666
#: InvenTree/settings.py:667
msgid "Norwegian"
msgstr "Norweski"
#: InvenTree/settings.py:667
#: InvenTree/settings.py:668
msgid "Polish"
msgstr "Polski"
#: InvenTree/settings.py:668
#: InvenTree/settings.py:669
msgid "Portugese"
msgstr "Portugalski"
#: InvenTree/settings.py:669
#: InvenTree/settings.py:670
msgid "Russian"
msgstr "Rosyjski"
#: InvenTree/settings.py:670
#: InvenTree/settings.py:671
msgid "Swedish"
msgstr "Szwedzki"
#: InvenTree/settings.py:671
#: InvenTree/settings.py:672
msgid "Thai"
msgstr "Tajski"
#: InvenTree/settings.py:672
#: InvenTree/settings.py:673
msgid "Turkish"
msgstr "Turecki"
#: InvenTree/settings.py:673
#: InvenTree/settings.py:674
msgid "Vietnamese"
msgstr "Wietnamski"
#: InvenTree/settings.py:674
#: InvenTree/settings.py:675
msgid "Chinese"
msgstr "Chiński"

View File

@ -3,8 +3,8 @@ msgid ""
msgstr ""
"Project-Id-Version: inventree\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-02-20 22:01+0000\n"
"PO-Revision-Date: 2022-02-20 22:02\n"
"POT-Creation-Date: 2022-02-22 01:07+0000\n"
"PO-Revision-Date: 2022-02-22 01:18\n"
"Last-Translator: \n"
"Language-Team: Portuguese\n"
"Language: pt_PT\n"
@ -328,54 +328,58 @@ msgid "Hebrew"
msgstr ""
#: InvenTree/settings.py:662
msgid "Italian"
msgid "Hungarian"
msgstr ""
#: InvenTree/settings.py:663
msgid "Japanese"
msgid "Italian"
msgstr ""
#: InvenTree/settings.py:664
msgid "Korean"
msgid "Japanese"
msgstr ""
#: InvenTree/settings.py:665
msgid "Dutch"
msgid "Korean"
msgstr ""
#: InvenTree/settings.py:666
msgid "Norwegian"
msgid "Dutch"
msgstr ""
#: InvenTree/settings.py:667
msgid "Polish"
msgid "Norwegian"
msgstr ""
#: InvenTree/settings.py:668
msgid "Portugese"
msgid "Polish"
msgstr ""
#: InvenTree/settings.py:669
msgid "Russian"
msgid "Portugese"
msgstr ""
#: InvenTree/settings.py:670
msgid "Swedish"
msgid "Russian"
msgstr ""
#: InvenTree/settings.py:671
msgid "Thai"
msgid "Swedish"
msgstr ""
#: InvenTree/settings.py:672
msgid "Turkish"
msgid "Thai"
msgstr ""
#: InvenTree/settings.py:673
msgid "Vietnamese"
msgid "Turkish"
msgstr ""
#: InvenTree/settings.py:674
msgid "Vietnamese"
msgstr ""
#: InvenTree/settings.py:675
msgid "Chinese"
msgstr ""

View File

@ -3,8 +3,8 @@ msgid ""
msgstr ""
"Project-Id-Version: inventree\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-02-20 22:01+0000\n"
"PO-Revision-Date: 2022-02-20 22:03\n"
"POT-Creation-Date: 2022-02-22 01:07+0000\n"
"PO-Revision-Date: 2022-02-22 01:18\n"
"Last-Translator: \n"
"Language-Team: Russian\n"
"Language: ru_RU\n"
@ -328,54 +328,58 @@ msgid "Hebrew"
msgstr "Иврит"
#: InvenTree/settings.py:662
msgid "Hungarian"
msgstr ""
#: InvenTree/settings.py:663
msgid "Italian"
msgstr "Итальянский"
#: InvenTree/settings.py:663
#: InvenTree/settings.py:664
msgid "Japanese"
msgstr "Японский"
#: InvenTree/settings.py:664
#: InvenTree/settings.py:665
msgid "Korean"
msgstr "Корейский"
#: InvenTree/settings.py:665
#: InvenTree/settings.py:666
msgid "Dutch"
msgstr "Голландский"
#: InvenTree/settings.py:666
#: InvenTree/settings.py:667
msgid "Norwegian"
msgstr "Норвежский"
#: InvenTree/settings.py:667
#: InvenTree/settings.py:668
msgid "Polish"
msgstr "Польский"
#: InvenTree/settings.py:668
#: InvenTree/settings.py:669
msgid "Portugese"
msgstr "Португальский"
#: InvenTree/settings.py:669
#: InvenTree/settings.py:670
msgid "Russian"
msgstr "Русский"
#: InvenTree/settings.py:670
#: InvenTree/settings.py:671
msgid "Swedish"
msgstr "Шведский"
#: InvenTree/settings.py:671
#: InvenTree/settings.py:672
msgid "Thai"
msgstr "Тайский"
#: InvenTree/settings.py:672
#: InvenTree/settings.py:673
msgid "Turkish"
msgstr "Турецкий"
#: InvenTree/settings.py:673
#: InvenTree/settings.py:674
msgid "Vietnamese"
msgstr "Вьетнамский"
#: InvenTree/settings.py:674
#: InvenTree/settings.py:675
msgid "Chinese"
msgstr "Китайский"

View File

@ -3,8 +3,8 @@ msgid ""
msgstr ""
"Project-Id-Version: inventree\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-02-20 22:01+0000\n"
"PO-Revision-Date: 2022-02-20 22:02\n"
"POT-Creation-Date: 2022-02-22 01:07+0000\n"
"PO-Revision-Date: 2022-02-22 01:18\n"
"Last-Translator: \n"
"Language-Team: Swedish\n"
"Language: sv_SE\n"
@ -328,54 +328,58 @@ msgid "Hebrew"
msgstr "Hebreiska"
#: InvenTree/settings.py:662
msgid "Hungarian"
msgstr ""
#: InvenTree/settings.py:663
msgid "Italian"
msgstr "Italienska"
#: InvenTree/settings.py:663
#: InvenTree/settings.py:664
msgid "Japanese"
msgstr "Japanska"
#: InvenTree/settings.py:664
#: InvenTree/settings.py:665
msgid "Korean"
msgstr "Koreanska"
#: InvenTree/settings.py:665
#: InvenTree/settings.py:666
msgid "Dutch"
msgstr "Nederländska"
#: InvenTree/settings.py:666
#: InvenTree/settings.py:667
msgid "Norwegian"
msgstr "Norska"
#: InvenTree/settings.py:667
#: InvenTree/settings.py:668
msgid "Polish"
msgstr "Polska"
#: InvenTree/settings.py:668
#: InvenTree/settings.py:669
msgid "Portugese"
msgstr ""
#: InvenTree/settings.py:669
#: InvenTree/settings.py:670
msgid "Russian"
msgstr "Ryska"
#: InvenTree/settings.py:670
#: InvenTree/settings.py:671
msgid "Swedish"
msgstr "Svenska"
#: InvenTree/settings.py:671
#: InvenTree/settings.py:672
msgid "Thai"
msgstr "Thailändska"
#: InvenTree/settings.py:672
#: InvenTree/settings.py:673
msgid "Turkish"
msgstr "Turkiska"
#: InvenTree/settings.py:673
#: InvenTree/settings.py:674
msgid "Vietnamese"
msgstr "Vietnamesiska"
#: InvenTree/settings.py:674
#: InvenTree/settings.py:675
msgid "Chinese"
msgstr "Kinesiska"

View File

@ -3,8 +3,8 @@ msgid ""
msgstr ""
"Project-Id-Version: inventree\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-02-20 22:01+0000\n"
"PO-Revision-Date: 2022-02-20 22:03\n"
"POT-Creation-Date: 2022-02-22 01:07+0000\n"
"PO-Revision-Date: 2022-02-22 01:18\n"
"Last-Translator: \n"
"Language-Team: Thai\n"
"Language: th_TH\n"
@ -328,54 +328,58 @@ msgid "Hebrew"
msgstr ""
#: InvenTree/settings.py:662
msgid "Italian"
msgid "Hungarian"
msgstr ""
#: InvenTree/settings.py:663
msgid "Japanese"
msgid "Italian"
msgstr ""
#: InvenTree/settings.py:664
msgid "Korean"
msgid "Japanese"
msgstr ""
#: InvenTree/settings.py:665
msgid "Dutch"
msgid "Korean"
msgstr ""
#: InvenTree/settings.py:666
msgid "Norwegian"
msgid "Dutch"
msgstr ""
#: InvenTree/settings.py:667
msgid "Polish"
msgid "Norwegian"
msgstr ""
#: InvenTree/settings.py:668
msgid "Portugese"
msgid "Polish"
msgstr ""
#: InvenTree/settings.py:669
msgid "Russian"
msgid "Portugese"
msgstr ""
#: InvenTree/settings.py:670
msgid "Swedish"
msgid "Russian"
msgstr ""
#: InvenTree/settings.py:671
msgid "Thai"
msgid "Swedish"
msgstr ""
#: InvenTree/settings.py:672
msgid "Turkish"
msgid "Thai"
msgstr ""
#: InvenTree/settings.py:673
msgid "Vietnamese"
msgid "Turkish"
msgstr ""
#: InvenTree/settings.py:674
msgid "Vietnamese"
msgstr ""
#: InvenTree/settings.py:675
msgid "Chinese"
msgstr ""

View File

@ -3,8 +3,8 @@ msgid ""
msgstr ""
"Project-Id-Version: inventree\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-02-20 22:01+0000\n"
"PO-Revision-Date: 2022-02-20 22:03\n"
"POT-Creation-Date: 2022-02-22 01:07+0000\n"
"PO-Revision-Date: 2022-02-22 01:18\n"
"Last-Translator: \n"
"Language-Team: Turkish\n"
"Language: tr_TR\n"
@ -328,54 +328,58 @@ msgid "Hebrew"
msgstr "İbranice"
#: InvenTree/settings.py:662
msgid "Hungarian"
msgstr ""
#: InvenTree/settings.py:663
msgid "Italian"
msgstr "İtalyanca"
#: InvenTree/settings.py:663
#: InvenTree/settings.py:664
msgid "Japanese"
msgstr "Japonca"
#: InvenTree/settings.py:664
#: InvenTree/settings.py:665
msgid "Korean"
msgstr "Korece"
#: InvenTree/settings.py:665
#: InvenTree/settings.py:666
msgid "Dutch"
msgstr "Flemenkçe"
#: InvenTree/settings.py:666
#: InvenTree/settings.py:667
msgid "Norwegian"
msgstr "Norveççe"
#: InvenTree/settings.py:667
#: InvenTree/settings.py:668
msgid "Polish"
msgstr "Polonyaca"
#: InvenTree/settings.py:668
#: InvenTree/settings.py:669
msgid "Portugese"
msgstr ""
#: InvenTree/settings.py:669
#: InvenTree/settings.py:670
msgid "Russian"
msgstr "Rusça"
#: InvenTree/settings.py:670
#: InvenTree/settings.py:671
msgid "Swedish"
msgstr "İsveççe"
#: InvenTree/settings.py:671
#: InvenTree/settings.py:672
msgid "Thai"
msgstr "Tay dili"
#: InvenTree/settings.py:672
#: InvenTree/settings.py:673
msgid "Turkish"
msgstr "Türkçe"
#: InvenTree/settings.py:673
#: InvenTree/settings.py:674
msgid "Vietnamese"
msgstr ""
#: InvenTree/settings.py:674
#: InvenTree/settings.py:675
msgid "Chinese"
msgstr "Çince"

View File

@ -3,8 +3,8 @@ msgid ""
msgstr ""
"Project-Id-Version: inventree\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-02-20 22:01+0000\n"
"PO-Revision-Date: 2022-02-20 22:02\n"
"POT-Creation-Date: 2022-02-22 01:07+0000\n"
"PO-Revision-Date: 2022-02-22 01:18\n"
"Last-Translator: \n"
"Language-Team: Vietnamese\n"
"Language: vi_VN\n"
@ -328,54 +328,58 @@ msgid "Hebrew"
msgstr ""
#: InvenTree/settings.py:662
msgid "Italian"
msgid "Hungarian"
msgstr ""
#: InvenTree/settings.py:663
msgid "Japanese"
msgid "Italian"
msgstr ""
#: InvenTree/settings.py:664
msgid "Korean"
msgid "Japanese"
msgstr ""
#: InvenTree/settings.py:665
msgid "Dutch"
msgid "Korean"
msgstr ""
#: InvenTree/settings.py:666
msgid "Norwegian"
msgid "Dutch"
msgstr ""
#: InvenTree/settings.py:667
msgid "Polish"
msgid "Norwegian"
msgstr ""
#: InvenTree/settings.py:668
msgid "Portugese"
msgid "Polish"
msgstr ""
#: InvenTree/settings.py:669
msgid "Russian"
msgid "Portugese"
msgstr ""
#: InvenTree/settings.py:670
msgid "Swedish"
msgid "Russian"
msgstr ""
#: InvenTree/settings.py:671
msgid "Thai"
msgid "Swedish"
msgstr ""
#: InvenTree/settings.py:672
msgid "Turkish"
msgid "Thai"
msgstr ""
#: InvenTree/settings.py:673
msgid "Vietnamese"
msgid "Turkish"
msgstr ""
#: InvenTree/settings.py:674
msgid "Vietnamese"
msgstr ""
#: InvenTree/settings.py:675
msgid "Chinese"
msgstr ""

View File

@ -3,8 +3,8 @@ msgid ""
msgstr ""
"Project-Id-Version: inventree\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-02-20 22:01+0000\n"
"PO-Revision-Date: 2022-02-20 22:02\n"
"POT-Creation-Date: 2022-02-22 01:07+0000\n"
"PO-Revision-Date: 2022-02-22 01:18\n"
"Last-Translator: \n"
"Language-Team: Chinese Simplified\n"
"Language: zh_CN\n"
@ -328,54 +328,58 @@ msgid "Hebrew"
msgstr "希伯来语"
#: InvenTree/settings.py:662
msgid "Hungarian"
msgstr ""
#: InvenTree/settings.py:663
msgid "Italian"
msgstr "意大利语"
#: InvenTree/settings.py:663
#: InvenTree/settings.py:664
msgid "Japanese"
msgstr "日语"
#: InvenTree/settings.py:664
#: InvenTree/settings.py:665
msgid "Korean"
msgstr "韩语"
#: InvenTree/settings.py:665
#: InvenTree/settings.py:666
msgid "Dutch"
msgstr "荷兰语"
#: InvenTree/settings.py:666
#: InvenTree/settings.py:667
msgid "Norwegian"
msgstr "挪威语"
#: InvenTree/settings.py:667
#: InvenTree/settings.py:668
msgid "Polish"
msgstr "波兰语"
#: InvenTree/settings.py:668
#: InvenTree/settings.py:669
msgid "Portugese"
msgstr ""
#: InvenTree/settings.py:669
#: InvenTree/settings.py:670
msgid "Russian"
msgstr "俄语"
#: InvenTree/settings.py:670
#: InvenTree/settings.py:671
msgid "Swedish"
msgstr "瑞典语"
#: InvenTree/settings.py:671
#: InvenTree/settings.py:672
msgid "Thai"
msgstr "泰语"
#: InvenTree/settings.py:672
#: InvenTree/settings.py:673
msgid "Turkish"
msgstr "土耳其语"
#: InvenTree/settings.py:673
#: InvenTree/settings.py:674
msgid "Vietnamese"
msgstr "越南语"
#: InvenTree/settings.py:674
#: InvenTree/settings.py:675
msgid "Chinese"
msgstr "中文(简体)"

View File

@ -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()

View File

@ -63,6 +63,43 @@ class StockLocation(InvenTreeTree):
help_text=_('Select Owner'),
related_name='stock_locations')
def get_location_owner(self):
"""
Get the closest "owner" for this location.
Start at this location, and traverse "up" the location tree until we find an owner
"""
for loc in self.get_ancestors(include_self=True, ascending=True):
if loc.owner is not None:
return loc.owner
return None
def check_ownership(self, user):
"""
Check if the user "owns" (is one of the owners of) the location.
"""
# Superuser accounts automatically "own" everything
if user.is_superuser:
return True
ownership_enabled = common.models.InvenTreeSetting.get_setting('STOCK_OWNERSHIP_CONTROL')
if not ownership_enabled:
# Location ownership function is not enabled, so return True
return True
owner = self.get_location_owner()
if owner is None:
# No owner set, for this location or any location above
# So, no ownership checks to perform!
return True
return user in owner.get_related_owners(include_group=True)
def get_absolute_url(self):
return reverse('stock-location-detail', kwargs={'pk': self.id})
@ -614,6 +651,48 @@ class StockItem(MPTTModel):
help_text=_('Select Owner'),
related_name='stock_items')
def get_item_owner(self):
"""
Return the closest "owner" for this StockItem.
- If the item has an owner set, return that
- If the item is "in stock", check the StockLocation
- Otherwise, return None
"""
if self.owner is not None:
return self.owner
if self.in_stock and self.location is not None:
loc_owner = self.location.get_location_owner()
if loc_owner:
return loc_owner
return None
def check_ownership(self, user):
"""
Check if the user "owns" (or is one of the owners of) the item
"""
# Superuser accounts automatically "own" everything
if user.is_superuser:
return True
ownership_enabled = common.models.InvenTreeSetting.get_setting('STOCK_OWNERSHIP_CONTROL')
if not ownership_enabled:
# Location ownership function is not enabled, so return True
return True
owner = self.get_item_owner()
if owner is None:
return True
return user in owner.get_related_owners(include_group=True)
def is_stale(self):
"""
Returns True if this Stock item is "stale".
@ -1311,6 +1390,7 @@ class StockItem(MPTTModel):
"""
notes = kwargs.get('notes', '')
code = kwargs.get('code', StockHistoryCode.SPLIT_FROM_PARENT)
# Do not split a serialized part
if self.serialized:
@ -1352,7 +1432,7 @@ class StockItem(MPTTModel):
# Add a new tracking item for the new stock item
new_stock.add_tracking_entry(
StockHistoryCode.SPLIT_FROM_PARENT,
code,
user,
notes=notes,
deltas={
@ -1530,7 +1610,7 @@ class StockItem(MPTTModel):
return True
@transaction.atomic
def take_stock(self, quantity, user, notes=''):
def take_stock(self, quantity, user, notes='', code=StockHistoryCode.STOCK_REMOVE):
"""
Remove items from stock
"""
@ -1550,7 +1630,7 @@ class StockItem(MPTTModel):
if self.updateQuantity(self.quantity - quantity):
self.add_tracking_entry(
StockHistoryCode.STOCK_REMOVE,
code,
user,
notes=notes,
deltas={

View File

@ -18,18 +18,11 @@
<h4>{% trans "Stock Tracking Information" %}</h4>
{% include "spacer.html" %}
<div class='btn-group' role='group'>
{% setting_object 'STOCK_OWNERSHIP_CONTROL' as owner_control %}
{% if owner_control.value == "True" %}
{% authorized_owners item.owner as owners %}
{% endif %}
<!-- Check permissions and owner -->
{% if owner_control.value == "False" or owner_control.value == "True" and user in owners %}
{% if roles.stock.change and not item.is_building %}
{% if user_owns_item and roles.stock.change and not item.is_building %}
<button class='btn btn-success' type='button' title='New tracking entry' id='new-entry'>
<span class='fas fa-plus-circle'></span> {% trans "New Entry" %}
</button>
{% endif %}
{% endif %}
</div>
</div>
</div>

View File

@ -59,14 +59,7 @@
</ul>
</div>
<!-- Stock adjustment menu -->
<!-- Check permissions and owner -->
{% 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 %}
<div class='btn-group'>
<button id='stock-actions' title='{% trans "Stock adjustment actions" %}' class='btn btn-outline-secondary dropdown-toggle' type='button' data-bs-toggle='dropdown'><span class='fas fa-boxes'></span> <span class='caret'></span></button>
@ -219,24 +212,8 @@
</tr>
</table>
{% setting_object 'STOCK_OWNERSHIP_CONTROL' as owner_control %}
{% if owner_control.value == "True" %}
{% authorized_owners item.owner as owners %}
{% endif %}
<div class='info-messages'>
{% setting_object 'STOCK_OWNERSHIP_CONTROL' as owner_control %}
{% if owner_control.value == "True" %}
{% authorized_owners item.owner as owners %}
{% if not user in owners and not user.is_superuser %}
<div class='alert alert-block alert-info'>
{% trans "You are not in the list of owners of this item. This stock item cannot be edited." %}<br>
</div>
{% endif %}
{% endif %}
{% if item.is_building %}
<div class='alert alert-block alert-info'>
{% trans "This stock item is in production and cannot be edited." %}<br>
@ -409,14 +386,28 @@
<tr>
<td><span class='fas fa-vial'></span></td>
<td>{% trans "Tests" %}</td>
<td>{{ item.requiredTestStatus.passed }} / {{ item.requiredTestStatus.total }}</td>
<td>
{{ item.requiredTestStatus.passed }} / {{ item.requiredTestStatus.total }}
{% if item.passedAllRequiredTests %}
<span class='fas fa-check-circle float-right icon-green'></span>
{% else %}
<span class='fas fa-times-circle float-right icon-red'></span>
{% endif %}
</td>
</tr>
{% endif %}
{% if item.owner %}
{% if ownership_enabled and item_owner %}
<tr>
<td><span class='fas fa-users'></span></td>
<td>{% trans "Owner" %}</td>
<td>{{ item.owner }}</td>
<td>
{{ item_owner }}
{% if not user_owns_item %}
<span class='badge rounded-pill bg-warning badge-right' title='{% trans "You are not in the list of owners of this item. This stock item cannot be edited." %}'>
{% trans "Read only" %}
</span>
{% endif %}
</td>
</tr>
{% endif %}
</table>

View File

@ -20,6 +20,7 @@
{% endblock %}
{% block actions %}
<!-- Admin view -->
{% if location and user.is_staff and roles.stock_location.change %}
{% url 'admin:stock_stocklocation_change' location.pk as url %}
@ -38,7 +39,7 @@
</ul>
</div>
<!-- Check permissions and owner -->
{% 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 %}
<div class='btn-group' role='group'>
<button id='stock-actions' title='{% trans "Stock actions" %}' class='btn btn-outline-secondary dropdown-toggle' type='button' data-bs-toggle='dropdown'>
@ -74,13 +75,11 @@
{% endif %}
{% endif %}
{% endif %}
{% if owner_control.value == "False" or owner_control.value == "True" and user in owners or user.is_superuser or not location %}
{% if roles.stock_location.add %}
{% if user_owns_location and roles.stock_location.add %}
<button class='btn btn-success' id='location-create' type='button' title='{% trans "Create new stock location" %}'>
<span class='fas fa-plus-circle'></span> {% trans "New Location" %}
</button>
{% endif %}
{% endif %}
{% endblock %}
{% block details_left %}
@ -106,23 +105,23 @@
<td><em>{% trans "Top level stock location" %}</em></td>
</tr>
{% endif %}
{% if ownership_enabled and location_owner %}
<tr>
<td><span class='fas fa-users'></span></td>
<td>{% trans "Location Owner" %}</td>
<td>
{{ location_owner }}
{% if not user_owns_location %}
<span class='badge rounded-pill bg-warning badge-right' title='{% trans "You are not in the list of owners of this location. This stock location cannot be edited." %}'>
{% trans "Read only" %}
</span>
{% endif %}
</td>
</tr>
{% endif %}
</table>
{% 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 %}
<div class='alert alert-block alert-info'>
{% trans "You are not in the list of owners of this location. This stock location cannot be edited." %}<br>
</div>
{% endif %}
{% endif %}
{% endblock details_below %}
{% block details_right %}
{% if location %}
<table class='table table-striped table-condensed'>

View File

@ -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):

View File

@ -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" %}';

View File

@ -452,7 +452,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:
@ -467,7 +467,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
@ -489,7 +489,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')

View File

@ -37,6 +37,9 @@ InvenTree is supported by a [companion mobile app](https://inventree.readthedocs
- [**Download InvenTree from the Apple App Store**](https://apps.apple.com/au/app/inventree/id1581731101#?platform=iphone)
# Deploy to DigitalOcean
[![Deploy to DO](https://www.deploytodo.com/do-btn-blue-ghost.svg)](https://marketplace.digitalocean.com/apps/inventree?refcode=d6172576d014)
# Documentation
For InvenTree documentation, refer to the [InvenTree documentation website](https://inventree.readthedocs.io/en/latest/).