From 357bfdae3f948eef98c967e8a7320d3f4feeab2c Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Tue, 21 May 2019 13:33:05 +1000 Subject: [PATCH 1/4] Add some test fixtures for Company app --- InvenTree/company/fixtures/company.yaml | 14 +++++++++ InvenTree/company/fixtures/supplier_part.yaml | 24 +++++++++++++++ InvenTree/company/tests.py | 29 ++++++++++++++++--- 3 files changed, 63 insertions(+), 4 deletions(-) create mode 100644 InvenTree/company/fixtures/company.yaml create mode 100644 InvenTree/company/fixtures/supplier_part.yaml diff --git a/InvenTree/company/fixtures/company.yaml b/InvenTree/company/fixtures/company.yaml new file mode 100644 index 0000000000..7f95b6ec26 --- /dev/null +++ b/InvenTree/company/fixtures/company.yaml @@ -0,0 +1,14 @@ +# Sample company data + +- model: company.company + fields: + name: ACME + description: A Cool Military Enterprise +- model: company.company + fields: + name: Appel Computers + description: Think more differenter +- model: company.company + fields: + name: Zerg Corp + description: We eat the competition \ No newline at end of file diff --git a/InvenTree/company/fixtures/supplier_part.yaml b/InvenTree/company/fixtures/supplier_part.yaml new file mode 100644 index 0000000000..8066375bf8 --- /dev/null +++ b/InvenTree/company/fixtures/supplier_part.yaml @@ -0,0 +1,24 @@ +# Supplier Parts + +# M2x4 LPHS from ACME +- model: company.supplierpart + pk: 1 + fields: + part: 1 + supplier: 1 + SKU: 'ACME0001' + +- model: company.supplierpart + pk: 2 + fields: + part: 1 + supplier: 1 + SKU: 'ACME0002' + +# M2x4 LPHS from Zerg Corp +- model: company.supplierpart + pk: 3 + fields: + part: 1 + supplier: 3 + SKU: 'ZERGLPHS' \ No newline at end of file diff --git a/InvenTree/company/tests.py b/InvenTree/company/tests.py index e5f5d99869..7b6661688d 100644 --- a/InvenTree/company/tests.py +++ b/InvenTree/company/tests.py @@ -8,6 +8,15 @@ from .models import rename_company_image class CompanySimpleTest(TestCase): + fixtures = [ + 'company', + 'category', + 'part', + 'location', + 'bom', + 'supplier_part', + ] + def setUp(self): Company.objects.create(name='ABC Co.', description='Seller of ABC products', @@ -17,7 +26,7 @@ class CompanySimpleTest(TestCase): is_supplier=True) def test_company_model(self): - c = Company.objects.get(pk=1) + c = Company.objects.get(name='ABC Co.') self.assertEqual(c.name, 'ABC Co.') self.assertEqual(str(c), 'ABC Co. - Seller of ABC products') @@ -34,9 +43,21 @@ class CompanySimpleTest(TestCase): self.assertEqual(rn, 'company_images' + os.path.sep + 'company_1_img') def test_part_count(self): - # Initially the company should have no associated parts - c = Company.objects.get(pk=1) - self.assertEqual(c.has_parts, False) + + acme = Company.objects.get(pk=1) + appel = Company.objects.get(pk=2) + zerg = Company.objects.get(pk=3) + + self.assertTrue(acme.has_parts) + self.assertEqual(acme.part_count, 2) + + self.assertFalse(appel.has_parts) + self.assertEqual(appel.part_count, 0) + + self.assertTrue(zerg.has_parts) + self.assertEqual(zerg.part_count, 1) + + # TODO - Add some supplier parts here From 6f73c379c2e32634674ea8ab08f4d2cad3a8ef9e Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Tue, 21 May 2019 13:51:43 +1000 Subject: [PATCH 2/4] Remove 'minimum' order from SupplierPart - This can be handled using the 'PriceBreak' set --- InvenTree/company/forms.py | 1 - .../0003_remove_supplierpart_minimum.py | 17 +++++++++++++++++ InvenTree/company/models.py | 7 ------- .../company/templates/company/partdetail.html | 3 --- 4 files changed, 17 insertions(+), 11 deletions(-) create mode 100644 InvenTree/company/migrations/0003_remove_supplierpart_minimum.py diff --git a/InvenTree/company/forms.py b/InvenTree/company/forms.py index 0ad63b9d63..76b1c1342c 100644 --- a/InvenTree/company/forms.py +++ b/InvenTree/company/forms.py @@ -57,7 +57,6 @@ class EditSupplierPartForm(HelperForm): 'note', 'base_cost', 'multiple', - 'minimum', 'packaging', 'lead_time' ] diff --git a/InvenTree/company/migrations/0003_remove_supplierpart_minimum.py b/InvenTree/company/migrations/0003_remove_supplierpart_minimum.py new file mode 100644 index 0000000000..21ec25ebbf --- /dev/null +++ b/InvenTree/company/migrations/0003_remove_supplierpart_minimum.py @@ -0,0 +1,17 @@ +# Generated by Django 2.2 on 2019-05-21 03:51 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('company', '0002_auto_20190520_2204'), + ] + + operations = [ + migrations.RemoveField( + model_name='supplierpart', + name='minimum', + ), + ] diff --git a/InvenTree/company/models.py b/InvenTree/company/models.py index be6cf10f7c..5c3b3291ff 100644 --- a/InvenTree/company/models.py +++ b/InvenTree/company/models.py @@ -173,7 +173,6 @@ class SupplierPart(models.Model): note: Longer form note field base_cost: Base charge added to order independent of quantity e.g. "Reeling Fee" multiple: Multiple that the part is provided in - minimum: MOQ (minimum order quantity) required for purchase lead_time: Supplier lead time packaging: packaging that the part is supplied in, e.g. "Reel" """ @@ -217,8 +216,6 @@ class SupplierPart(models.Model): multiple = models.PositiveIntegerField(default=1, validators=[MinValueValidator(1)], help_text='Order multiple') - minimum = models.PositiveIntegerField(default=1, validators=[MinValueValidator(1)], help_text='Minimum order quantity (MOQ)') - lead_time = models.DurationField(blank=True, null=True) @property @@ -256,10 +253,6 @@ class SupplierPart(models.Model): if len(price_breaks) == 0: return None - # Minimum ordering requirement - if moq and self.minimum > quantity: - quantity = self.minimum - # Order multiples if multiples: quantity = int(math.ceil(quantity / self.multiple) * self.multiple) diff --git a/InvenTree/company/templates/company/partdetail.html b/InvenTree/company/templates/company/partdetail.html index 5d0eee89a9..812ceacf04 100644 --- a/InvenTree/company/templates/company/partdetail.html +++ b/InvenTree/company/templates/company/partdetail.html @@ -66,9 +66,6 @@ InvenTree | {{ company.name }} - Parts {% if part.base_cost > 0 %} Base Price (Flat Fee){{ part.base_cost }} {% endif %} - {% if part.minimum > 1 %} - Minimum Order Quantity{{ part.minimum }} - {% endif %} Price Breaks From cdcc4f9ca19a68200b2a761b5334ff454254d289 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Tue, 21 May 2019 13:53:25 +1000 Subject: [PATCH 3/4] Simple tests for price breaks --- InvenTree/company/fixtures/price_breaks.yaml | 47 +++++++++++++++++++ InvenTree/company/fixtures/supplier_part.yaml | 9 +++- InvenTree/company/tests.py | 39 +++++++++++++-- 3 files changed, 90 insertions(+), 5 deletions(-) create mode 100644 InvenTree/company/fixtures/price_breaks.yaml diff --git a/InvenTree/company/fixtures/price_breaks.yaml b/InvenTree/company/fixtures/price_breaks.yaml new file mode 100644 index 0000000000..c16702a7a3 --- /dev/null +++ b/InvenTree/company/fixtures/price_breaks.yaml @@ -0,0 +1,47 @@ +# Price breaks for supplier parts + +# Price breaks for ACME0001 + +- model: company.supplierpricebreak + fields: + part: 1 + quantity: 1 + cost: 10 + +- model: company.supplierpricebreak + fields: + part: 1 + quantity: 5 + cost: 7.50 + +- model: company.supplierpricebreak + fields: + part: 1 + quantity: 25 + cost: 3.50 + +# Price breaks for ACME0002 +- model: company.supplierpricebreak + fields: + part: 2 + quantity: 5 + cost: 7.00 + +- model: company.supplierpricebreak + fields: + part: 2 + quantity: 50 + cost: 1.25 + +# Price breaks for ZERGLPHS +- model: company.supplierpricebreak + fields: + part: 3 + quantity: 5 + cost: 8 + +- model: company.supplierpricebreak + fields: + part: 3 + quantity: 100 + cost: 1.25 \ No newline at end of file diff --git a/InvenTree/company/fixtures/supplier_part.yaml b/InvenTree/company/fixtures/supplier_part.yaml index 8066375bf8..f0076974d5 100644 --- a/InvenTree/company/fixtures/supplier_part.yaml +++ b/InvenTree/company/fixtures/supplier_part.yaml @@ -21,4 +21,11 @@ fields: part: 1 supplier: 3 - SKU: 'ZERGLPHS' \ No newline at end of file + SKU: 'ZERGLPHS' + +- model: company.supplierpart + pk: 4 + fields: + part: 2 + supplier: 2 + SKU: 'ZERGM312' diff --git a/InvenTree/company/tests.py b/InvenTree/company/tests.py index 7b6661688d..56adb2f9ef 100644 --- a/InvenTree/company/tests.py +++ b/InvenTree/company/tests.py @@ -2,7 +2,7 @@ from django.test import TestCase import os -from .models import Company, Contact +from .models import Company, Contact, SupplierPart, SupplierPriceBreak from .models import rename_company_image @@ -15,6 +15,7 @@ class CompanySimpleTest(TestCase): 'location', 'bom', 'supplier_part', + 'price_breaks', ] def setUp(self): @@ -25,6 +26,11 @@ class CompanySimpleTest(TestCase): is_customer=False, is_supplier=True) + self.acme0001 = SupplierPart.objects.get(SKU='ACME0001') + self.acme0002 = SupplierPart.objects.get(SKU='ACME0002') + self.zerglphs = SupplierPart.objects.get(SKU='ZERGLPHS') + self.zergm312 = SupplierPart.objects.get(SKU='ZERGM312') + def test_company_model(self): c = Company.objects.get(name='ABC Co.') self.assertEqual(c.name, 'ABC Co.') @@ -51,15 +57,40 @@ class CompanySimpleTest(TestCase): self.assertTrue(acme.has_parts) self.assertEqual(acme.part_count, 2) - self.assertFalse(appel.has_parts) - self.assertEqual(appel.part_count, 0) + self.assertTrue(appel.has_parts) + self.assertEqual(appel.part_count, 1) self.assertTrue(zerg.has_parts) self.assertEqual(zerg.part_count, 1) + def test_price_breaks(self): + + self.assertTrue(self.acme0001.has_price_breaks) + self.assertTrue(self.acme0002.has_price_breaks) + self.assertTrue(self.zerglphs.has_price_breaks) + self.assertFalse(self.zergm312.has_price_breaks) + self.assertEqual(self.acme0001.price_breaks.count(), 3) + self.assertEqual(self.acme0002.price_breaks.count(), 2) + self.assertEqual(self.zerglphs.price_breaks.count(), 2) + self.assertEqual(self.zergm312.price_breaks.count(), 0) - # TODO - Add some supplier parts here + def test_quantity_pricing(self): + """ Simple test for quantity pricing """ + + p = self.acme0001.get_price + self.assertEqual(p(1), 10) + self.assertEqual(p(4), 40) + self.assertEqual(p(11), 82.5) + self.assertEqual(p(23), 172.5) + self.assertEqual(p(100), 350) + + p = self.acme0002.get_price + self.assertEqual(p(1), None) + self.assertEqual(p(2), None) + self.assertEqual(p(5), 35) + self.assertEqual(p(45), 315) + self.assertEqual(p(55), 68.75) class ContactSimpleTest(TestCase): From 2817e6ca31a0883d88f46c5a4bb34ff8a503ae51 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Tue, 21 May 2019 14:08:40 +1000 Subject: [PATCH 4/4] Added further part pricing --- InvenTree/company/fixtures/price_breaks.yaml | 6 ++--- InvenTree/company/tests.py | 26 ++++++++++++++++---- InvenTree/part/models.py | 2 +- InvenTree/part/test_part.py | 4 +++ 4 files changed, 29 insertions(+), 9 deletions(-) diff --git a/InvenTree/company/fixtures/price_breaks.yaml b/InvenTree/company/fixtures/price_breaks.yaml index c16702a7a3..6616ab36b1 100644 --- a/InvenTree/company/fixtures/price_breaks.yaml +++ b/InvenTree/company/fixtures/price_breaks.yaml @@ -36,12 +36,12 @@ # Price breaks for ZERGLPHS - model: company.supplierpricebreak fields: - part: 3 - quantity: 5 + part: 4 + quantity: 25 cost: 8 - model: company.supplierpricebreak fields: - part: 3 + part: 4 quantity: 100 cost: 1.25 \ No newline at end of file diff --git a/InvenTree/company/tests.py b/InvenTree/company/tests.py index 56adb2f9ef..b100710fc4 100644 --- a/InvenTree/company/tests.py +++ b/InvenTree/company/tests.py @@ -2,8 +2,9 @@ from django.test import TestCase import os -from .models import Company, Contact, SupplierPart, SupplierPriceBreak +from .models import Company, Contact, SupplierPart from .models import rename_company_image +from part.models import Part class CompanySimpleTest(TestCase): @@ -67,13 +68,13 @@ class CompanySimpleTest(TestCase): self.assertTrue(self.acme0001.has_price_breaks) self.assertTrue(self.acme0002.has_price_breaks) - self.assertTrue(self.zerglphs.has_price_breaks) - self.assertFalse(self.zergm312.has_price_breaks) + self.assertTrue(self.zergm312.has_price_breaks) + self.assertFalse(self.zerglphs.has_price_breaks) self.assertEqual(self.acme0001.price_breaks.count(), 3) self.assertEqual(self.acme0002.price_breaks.count(), 2) - self.assertEqual(self.zerglphs.price_breaks.count(), 2) - self.assertEqual(self.zergm312.price_breaks.count(), 0) + self.assertEqual(self.zerglphs.price_breaks.count(), 0) + self.assertEqual(self.zergm312.price_breaks.count(), 2) def test_quantity_pricing(self): """ Simple test for quantity pricing """ @@ -92,6 +93,21 @@ class CompanySimpleTest(TestCase): self.assertEqual(p(45), 315) self.assertEqual(p(55), 68.75) + def test_part_pricing(self): + m2x4 = Part.objects.get(name='M2x4 LPHS') + + self.assertEqual(m2x4.get_price_info(10), "70.00000 - 75.00000") + self.assertEqual(m2x4.get_price_info(100), "125.00000 - 350.00000") + + pmin, pmax = m2x4.get_price_range(5) + self.assertEqual(pmin, 35) + self.assertEqual(pmax, 37.5) + + m3x12 = Part.objects.get(name='M3x12 SHCS') + + self.assertIsNone(m3x12.get_price_info(3)) + self.assertIsNotNone(m3x12.get_price_info(50)) + class ContactSimpleTest(TestCase): diff --git a/InvenTree/part/models.py b/InvenTree/part/models.py index af23b7484b..1d1d1b4fec 100644 --- a/InvenTree/part/models.py +++ b/InvenTree/part/models.py @@ -710,7 +710,7 @@ class Part(models.Model): if kwargs.get('image', True): if other.image: image_file = ContentFile(other.image.read()) - image_file.name = rename_part_image(self, 'test.png') + image_file.name = rename_part_image(self, other.image.url) self.image = image_file diff --git a/InvenTree/part/test_part.py b/InvenTree/part/test_part.py index 486d7c5684..8e69c8681d 100644 --- a/InvenTree/part/test_part.py +++ b/InvenTree/part/test_part.py @@ -68,3 +68,7 @@ class PartTest(TestCase): barcode = self.R1.format_barcode() self.assertIn('InvenTree', barcode) self.assertIn(self.R1.name, barcode) + + def test_copy(self): + + self.R2.deepCopy(self.R1, image=True, bom=True)