2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-04-29 03:56:43 +00:00

Add option to add a single-quantity price-break when creating a new SupplierPart object

- Add unit testing!
This commit is contained in:
Oliver Walters 2020-11-12 21:36:32 +11:00
parent 534f43872f
commit 47cbf3071d
5 changed files with 162 additions and 6 deletions

View File

@ -14,7 +14,6 @@ import django.forms
import djmoney.settings import djmoney.settings
from djmoney.forms.fields import MoneyField from djmoney.forms.fields import MoneyField
from common.models import InvenTreeSetting
import common.settings import common.settings
from .models import Company from .models import Company

View File

@ -380,6 +380,25 @@ class SupplierPart(models.Model):
def unit_pricing(self): def unit_pricing(self):
return self.get_price(1) return self.get_price(1)
def add_price_break(self, quantity, price):
"""
Create a new price break for this part
args:
quantity - Numerical quantity
price - Must be a Money object
"""
# Check if a price break at that quantity already exists...
if self.price_breaks.filter(quantity=quantity, part=self.pk).exists():
return
SupplierPriceBreak.objects.create(
part=self,
quantity=quantity,
price=price
)
def get_price(self, quantity, moq=True, multiples=True, currency=None): def get_price(self, quantity, moq=True, multiples=True, currency=None):
""" Calculate the supplier price based on quantity price breaks. """ Calculate the supplier price based on quantity price breaks.

View File

@ -3,6 +3,8 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals from __future__ import unicode_literals
import json
from django.test import TestCase from django.test import TestCase
from django.urls import reverse from django.urls import reverse
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
@ -11,7 +13,7 @@ from django.contrib.auth.models import Group
from .models import SupplierPart from .models import SupplierPart
class CompanyViewTest(TestCase): class CompanyViewTestBase(TestCase):
fixtures = [ fixtures = [
'category', 'category',
@ -47,14 +49,105 @@ class CompanyViewTest(TestCase):
self.client.login(username='username', password='password') self.client.login(username='username', password='password')
def test_company_index(self):
""" Test the company index """
response = self.client.get(reverse('company-index')) class SupplierPartViewTests(CompanyViewTestBase):
"""
Tests for the SupplierPart views.
"""
def post(self, data, valid=None):
"""
POST against this form and return the response (as a JSON object)
"""
url = reverse('supplier-part-create')
response = self.client.post(url, data, HTTP_X_REQUESTED_WITH='XMLHttpRequest')
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
json_data = json.loads(response.content)
# If a particular status code is required
if valid is not None:
if valid:
self.assertEqual(json_data['form_valid'], True)
else:
self.assertEqual(json_data['form_valid'], False)
form_errors = json.loads(json_data['form_errors'])
return json_data, form_errors
def test_supplier_part_create(self):
"""
Test the SupplierPartCreate view.
This view allows some additional functionality,
specifically it allows the user to create a single-quantity price break
automatically, when saving the new SupplierPart model.
"""
url = reverse('supplier-part-create')
# First check that we can GET the form
response = self.client.get(url, HTTP_X_REQUESTED_WITH='XMLHttpRequest')
self.assertEqual(response.status_code, 200)
# How many supplier parts are already in the database?
n = SupplierPart.objects.all().count()
data = {
'part': 1,
'supplier': 1,
}
# SKU is required! (form should fail)
(response, errors) = self.post(data, valid=False)
self.assertIsNotNone(errors.get('SKU', None))
data['SKU'] = 'TEST-ME-123'
(response, errors) = self.post(data, valid=True)
# Check that the SupplierPart was created!
self.assertEqual(n + 1, SupplierPart.objects.all().count())
# Check that it was created *without* a price-break
supplier_part = SupplierPart.objects.get(pk=response['pk'])
self.assertEqual(supplier_part.price_breaks.count(), 0)
# Duplicate SKU is prohibited
(response, errors) = self.post(data, valid=False)
self.assertIsNotNone(errors.get('__all__', None))
# Add with a different SKU, *and* a single-quantity price
data['SKU'] = 'TEST-ME-1234'
data['single_pricing_0'] = '123.4'
data['single_pricing_1'] = 'CAD'
(response, errors) = self.post(data, valid=True)
pk = response.get('pk')
# Check that *another* SupplierPart was created
self.assertEqual(n + 2, SupplierPart.objects.all().count())
supplier_part = SupplierPart.objects.get(pk=pk)
# Check that a price-break has been created!
self.assertEqual(supplier_part.price_breaks.count(), 1)
price_break = supplier_part.price_breaks.first()
self.assertEqual(price_break.quantity, 1)
def test_supplier_part_delete(self): def test_supplier_part_delete(self):
""" Test the SupplierPartDelete view """ """
Test the SupplierPartDelete view
"""
url = reverse('supplier-part-delete') url = reverse('supplier-part-delete')
@ -80,3 +173,15 @@ class CompanyViewTest(TestCase):
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
self.assertEqual(n - 2, SupplierPart.objects.count()) self.assertEqual(n - 2, SupplierPart.objects.count())
class CompanyViewTest(CompanyViewTestBase):
"""
Tests for various 'Company' views
"""
def test_company_index(self):
""" Test the company index """
response = self.client.get(reverse('company-index'))
self.assertEqual(response.status_code, 200)

View File

@ -271,6 +271,14 @@ class SupplierPartEdit(AjaxUpdateView):
ajax_form_title = _('Edit Supplier Part') ajax_form_title = _('Edit Supplier Part')
role_required = 'purchase_order.change' role_required = 'purchase_order.change'
def get_form(self):
form = super().get_form()
# Hide the single-pricing field (only for creating a new SupplierPart!)
form.fields['single_pricing'].widget = HiddenInput()
return form
class SupplierPartCreate(AjaxCreateView): class SupplierPartCreate(AjaxCreateView):
""" Create view for making new SupplierPart """ """ Create view for making new SupplierPart """
@ -282,6 +290,30 @@ class SupplierPartCreate(AjaxCreateView):
context_object_name = 'part' context_object_name = 'part'
role_required = 'purchase_order.add' role_required = 'purchase_order.add'
def validate(self, part, form):
single_pricing = form.cleaned_data.get('single_pricing', None)
if single_pricing:
# TODO - What validation steps can be performed on the single_pricing field?
pass
def save(self, form):
"""
If single_pricing is defined, add a price break for quantity=1
"""
# Save the supplier part object
supplier_part = super().save(form)
single_pricing = form.cleaned_data.get('single_pricing', None)
if single_pricing:
supplier_part.add_price_break(1, single_pricing)
return supplier_part
def get_form(self): def get_form(self):
""" Create Form instance to create a new SupplierPart object. """ Create Form instance to create a new SupplierPart object.
Hide some fields if they are not appropriate in context Hide some fields if they are not appropriate in context

View File

@ -8,6 +8,7 @@
category: 8 category: 8
link: www.acme.com/parts/m2x4lphs link: www.acme.com/parts/m2x4lphs
tree_id: 0 tree_id: 0
purchaseable: True
level: 0 level: 0
lft: 0 lft: 0
rght: 0 rght: 0