2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-06-15 03:25:42 +00:00

Rename "pack_units" to "pack_quantity"

This commit is contained in:
Oliver Walters
2023-05-22 01:18:37 +10:00
parent 532f592397
commit 4fcdbcafeb
13 changed files with 51 additions and 50 deletions

View File

@ -8,7 +8,7 @@ INVENTREE_API_VERSION = 117
Increment this API version number whenever there is a significant change to the API that any clients need to know about
v117 -> 2023-05-22 : https://github.com/inventree/InvenTree/pull/4854
- Replaces SupplierPart "pack_size" field with "pack_units"
- Replaces SupplierPart "pack_size" field with "pack_quantity"
- New field supports physical units, and allows for conversion between compatible units
v116 -> 2023-05-18 : https://github.com/inventree/InvenTree/pull/4823

View File

@ -390,7 +390,7 @@ class SupplierPartList(ListCreateDestroyAPIView):
'manufacturer',
'MPN',
'packaging',
'pack_units',
'pack_quantity',
'in_stock',
'updated',
]
@ -400,7 +400,7 @@ class SupplierPartList(ListCreateDestroyAPIView):
'supplier': 'supplier__name',
'manufacturer': 'manufacturer_part__manufacturer__name',
'MPN': 'manufacturer_part__MPN',
'pack_units': ['pack_units_native', 'pack_units'],
'pack_quantity': ['pack_quantity_native', 'pack_quantity'],
}
search_fields = [

View File

@ -66,4 +66,4 @@
part: 4
supplier: 2
SKU: 'R_4K7_0603.100PCK'
pack_units: '100'
pack_quantity: '100'

View File

@ -14,12 +14,12 @@ class Migration(migrations.Migration):
operations = [
migrations.AddField(
model_name='supplierpart',
name='pack_units',
field=models.CharField(blank=True, help_text='Units of measure for this supplier part', max_length=25, verbose_name='Packaging Units'),
name='pack_quantity',
field=models.CharField(blank=True, help_text='Total quantity supplied in a single pack. Leave empty for single items.', max_length=25, verbose_name='Pack Quantity'),
),
migrations.AddField(
model_name='supplierpart',
name='pack_units_native',
name='pack_quantity_native',
field=InvenTree.fields.RoundingDecimalField(decimal_places=10, default=1, max_digits=20, null=True),
),
]

View File

@ -14,8 +14,8 @@ def update_supplier_part_units(apps, schema_editor):
for sp in supplier_parts:
pack_size = normalize(sp.pack_size)
sp.pack_units = str(pack_size)
sp.pack_units_native = pack_size
sp.pack_quantity = str(pack_size)
sp.pack_quantity_native = pack_size
sp.save()
if supplier_parts.count() > 0:

View File

@ -438,8 +438,8 @@ class SupplierPart(MetadataMixin, InvenTreeBarcodeMixin, common.models.MetaMixin
multiple: Multiple that the part is provided in
lead_time: Supplier lead time
packaging: packaging that the part is supplied in, e.g. "Reel"
pack_units: Quantity of item supplied in a single pack (e.g. 30ml in a single tube)
pack_units_native: Pack units, converted to "native" units of the referenced part
pack_quantity: Quantity of item supplied in a single pack (e.g. 30ml in a single tube)
pack_quantity_native: Pack quantity, converted to "native" units of the referenced part
updated: Date that the SupplierPart was last updated
"""
@ -478,38 +478,38 @@ class SupplierPart(MetadataMixin, InvenTreeBarcodeMixin, common.models.MetaMixin
"""
super().clean()
self.pack_units = self.pack_units.strip()
self.pack_quantity = self.pack_quantity.strip()
# An empty 'pack_units' value is equivalent to '1'
if self.pack_units == '':
self.pack_units = '1'
# An empty 'pack_quantity' value is equivalent to '1'
if self.pack_quantity == '':
self.pack_quantity = '1'
# Validate that the UOM is compatible with the base part
if self.pack_units and self.part:
if self.pack_quantity and self.part:
try:
# Attempt conversion to specified unit
native_value = InvenTree.conversion.convert_physical_value(
self.pack_units, self.part.units
self.pack_quantity, self.part.units
)
# If part units are not provided, value must be dimensionless
if not self.part.units and native_value.units not in ['', 'dimensionless']:
raise ValidationError({
'pack_units': _("Pack units must be compatible with the base part units")
'pack_quantity': _("Pack units must be compatible with the base part units")
})
# Native value must be greater than zero
if float(native_value.magnitude) <= 0:
raise ValidationError({
'pack_units': _("Pack units must be greater than zero")
'pack_quantity': _("Pack units must be greater than zero")
})
# Update native pack units value
self.pack_units_native = Decimal(native_value.magnitude)
self.pack_quantity_native = Decimal(native_value.magnitude)
except ValidationError as e:
raise ValidationError({
'pack_units': e.messages
'pack_quantity': e.messages
})
# Ensure that the linked manufacturer_part points to the same part!
@ -601,14 +601,14 @@ class SupplierPart(MetadataMixin, InvenTreeBarcodeMixin, common.models.MetaMixin
packaging = models.CharField(max_length=50, blank=True, null=True, verbose_name=_('Packaging'), help_text=_('Part packaging'))
pack_units = models.CharField(
pack_quantity = models.CharField(
max_length=25,
verbose_name=_('Packaging Units'),
help_text=_('Units of measure for this supplier part'),
verbose_name=_('Pack Quantity'),
help_text=_('Total quantity supplied in a single pack. Leave empty for single items.'),
blank=True,
)
pack_units_native = RoundingDecimalField(
pack_quantity_native = RoundingDecimalField(
max_digits=20, decimal_places=10, default=1,
null=True,
)

View File

@ -265,7 +265,8 @@ class SupplierPartSerializer(InvenTreeTagModelSerializer):
'pk',
'barcode_hash',
'packaging',
'pack_units',
'pack_quantity',
'pack_quantity_native',
'part',
'part_detail',
'pretty_name',

View File

@ -162,7 +162,7 @@ src="{% static 'img/blank_image.png' %}"
<td>{{ part.packaging }}{% include "clip.html" %}</td>
</tr>
{% endif %}
{% if part.pack_units %}
{% if part.pack_quantity %}
<tr>
<td><span class='fas fa-box'></span></td>
<td>
@ -174,10 +174,10 @@ src="{% static 'img/blank_image.png' %}"
{% endif %}
</td>
<td>
{{ part.pack_units }}
{{ part.pack_quantity }}
{% include "clip.html" %}
{% if part.part.units and part.pack_units_native %}
<span class='fas fa-info-circle float-right' title='{% decimal part.pack_units_native %} {{ part.part.units }}'></span>
{% if part.part.units and part.pack_quantity_native %}
<span class='fas fa-info-circle float-right' title='{% decimal part.pack_quantity_native %} {{ part.part.units }}'></span>
{% endif %}
</td>
</tr>

View File

@ -10,10 +10,10 @@ from part.models import Part
class SupplierPartPackUnitsTests(InvenTreeTestCase):
"""Unit tests for the SupplierPart pack_units field"""
"""Unit tests for the SupplierPart pack_quantity field"""
def test_pack_units_dimensionless(self):
"""Test valid values for the 'pack_units' field"""
def test_pack_quantity_dimensionless(self):
"""Test valid values for the 'pack_quantity' field"""
# Create a part without units (dimensionless)
part = Part.objects.create(name='Test Part', description='Test part description', component=True)
@ -48,17 +48,17 @@ class SupplierPartPackUnitsTests(InvenTreeTestCase):
]
for test, expected in pass_tests.items():
sp.pack_units = test
sp.pack_quantity = test
sp.full_clean()
self.assertEqual(sp.pack_units_native, expected)
self.assertEqual(sp.pack_quantity_native, expected)
for test in fail_tests:
sp.pack_units = test
sp.pack_quantity = test
with self.assertRaises(ValidationError):
sp.full_clean()
def test_pack_units(self):
"""Test pack_units for a part with a specified dimension"""
def test_pack_quantity(self):
"""Test pack_quantity for a part with a specified dimension"""
# Create a part with units 'm'
part = Part.objects.create(name='Test Part', description='Test part description', component=True, units='m')
@ -101,14 +101,14 @@ class SupplierPartPackUnitsTests(InvenTreeTestCase):
]
for test, expected in pass_tests.items():
sp.pack_units = test
sp.pack_quantity = test
sp.full_clean()
self.assertEqual(
round(Decimal(sp.pack_units_native), 10),
round(Decimal(sp.pack_quantity_native), 10),
round(Decimal(str(expected)), 10)
)
for test in fail_tests:
sp.pack_units = test
sp.pack_quantity = test
with self.assertRaises(ValidationError):
sp.full_clean()

View File

@ -656,7 +656,7 @@ class PurchaseOrder(TotalPriceMixin, Order):
)
# Update the number of parts received against the particular line item
# Note that this quantity does *not* take the pack_size into account, it is "number of packs"
# Note that this quantity does *not* take the pack_quantity into account, it is "number of packs"
line.received += quantity
line.save()

View File

@ -228,7 +228,7 @@ class OrderTest(TestCase):
part=prt,
supplier=sup,
SKU='SKUx10',
pack_units='10',
pack_quantity='10',
)
# Create a new supplier part with smaller pack size
@ -236,7 +236,7 @@ class OrderTest(TestCase):
part=prt,
supplier=sup,
SKU='SKUx0.1',
pack_units='0.1',
pack_quantity='0.1',
)
# Record values before we start

View File

@ -63,14 +63,14 @@ class PartPricingTests(InvenTreeTestCase):
supplier=self.supplier_2,
part=self.part,
SKU='SUP_2',
pack_units='2.5',
pack_quantity='2.5',
)
self.sp_3 = company.models.SupplierPart.objects.create(
supplier=self.supplier_2,
part=self.part,
SKU='SUP_3',
pack_units='10'
pack_quantity='10'
)
company.models.SupplierPriceBreak.objects.create(
@ -322,7 +322,7 @@ class PartPricingTests(InvenTreeTestCase):
# $5 AUD each
line_1 = po.add_line_item(self.sp_2, quantity=10, purchase_price=Money(5, 'AUD'))
# $30 CAD each (but pack_units is 10, so really $3 CAD each)
# $30 CAD each (but pack_size is 10, so really $3 CAD each)
line_2 = po.add_line_item(self.sp_3, quantity=5, purchase_price=Money(30, 'CAD'))
pricing.update_purchase_cost()

View File

@ -138,7 +138,7 @@ function supplierPartFields(options={}) {
packaging: {
icon: 'fa-box',
},
pack_units: {},
pack_quantity: {},
};
if (options.part) {
@ -1242,8 +1242,8 @@ function loadSupplierPartTable(table, url, options) {
sortable: true,
},
{
field: 'pack_units',
title: '{% trans "Pack Units" %}',
field: 'pack_quantity',
title: '{% trans "Pack Quantity" %}',
sortable: true,
formatter: function(value, row) {
var output = `${value}`;