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/price_breaks.yaml b/InvenTree/company/fixtures/price_breaks.yaml new file mode 100644 index 0000000000..6616ab36b1 --- /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: 4 + quantity: 25 + cost: 8 + +- model: company.supplierpricebreak + fields: + part: 4 + 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 new file mode 100644 index 0000000000..f0076974d5 --- /dev/null +++ b/InvenTree/company/fixtures/supplier_part.yaml @@ -0,0 +1,31 @@ +# 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' + +- model: company.supplierpart + pk: 4 + fields: + part: 2 + supplier: 2 + SKU: 'ZERGM312' 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 diff --git a/InvenTree/company/tests.py b/InvenTree/company/tests.py index e5f5d99869..b100710fc4 100644 --- a/InvenTree/company/tests.py +++ b/InvenTree/company/tests.py @@ -2,12 +2,23 @@ from django.test import TestCase import os -from .models import Company, Contact +from .models import Company, Contact, SupplierPart from .models import rename_company_image +from part.models import Part class CompanySimpleTest(TestCase): + fixtures = [ + 'company', + 'category', + 'part', + 'location', + 'bom', + 'supplier_part', + 'price_breaks', + ] + def setUp(self): Company.objects.create(name='ABC Co.', description='Seller of ABC products', @@ -16,8 +27,13 @@ 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(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,11 +50,63 @@ 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) - # TODO - Add some supplier parts here + 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.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.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(), 0) + self.assertEqual(self.zergm312.price_breaks.count(), 2) + + 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) + + 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)