mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
Merge remote-tracking branch 'inventree/master'
This commit is contained in:
commit
d1dc0fae19
@ -4,8 +4,8 @@ omit =
|
|||||||
# Do not run coverage on migration files
|
# Do not run coverage on migration files
|
||||||
*/migrations/*
|
*/migrations/*
|
||||||
InvenTree/manage.py
|
InvenTree/manage.py
|
||||||
InvenTree/keygen.py
|
InvenTree/setup.py
|
||||||
Inventree/InvenTree/middleware.py
|
InvenTree/InvenTree/middleware.py
|
||||||
Inventree/InvenTree/utils.py
|
InvenTree/InvenTree/utils.py
|
||||||
Inventree/InvenTree/wsgi.py
|
InvenTree/InvenTree/wsgi.py
|
||||||
InvenTree/users/apps.py
|
InvenTree/users/apps.py
|
@ -159,7 +159,19 @@ WSGI_APPLICATION = 'InvenTree.wsgi.application'
|
|||||||
|
|
||||||
DATABASES = {}
|
DATABASES = {}
|
||||||
|
|
||||||
|
"""
|
||||||
|
When running unit tests, enforce usage of sqlite3 database,
|
||||||
|
so that the tests can be run in RAM without any setup requirements
|
||||||
|
"""
|
||||||
|
if 'test' in sys.argv:
|
||||||
|
eprint('Running tests - Using sqlite3 memory database')
|
||||||
|
DATABASES['default'] = {
|
||||||
|
'ENGINE': 'django.db.backends.sqlite3',
|
||||||
|
'NAME': 'test_db.sqlite3'
|
||||||
|
}
|
||||||
|
|
||||||
# Database backend selection
|
# Database backend selection
|
||||||
|
else:
|
||||||
if 'database' in CONFIG:
|
if 'database' in CONFIG:
|
||||||
DATABASES['default'] = CONFIG['database']
|
DATABASES['default'] = CONFIG['database']
|
||||||
else:
|
else:
|
||||||
|
21
InvenTree/build/fixtures/build.yaml
Normal file
21
InvenTree/build/fixtures/build.yaml
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
# Construct build objects
|
||||||
|
|
||||||
|
- model: build.build
|
||||||
|
fields:
|
||||||
|
part: 25
|
||||||
|
batch: 'B1'
|
||||||
|
title: 'Building 7 parts'
|
||||||
|
quantity: 7
|
||||||
|
notes: 'Some simple notes'
|
||||||
|
status: 10 # PENDING
|
||||||
|
creation_date: '2019-03-16'
|
||||||
|
|
||||||
|
- model: build.build
|
||||||
|
fields:
|
||||||
|
part: 50
|
||||||
|
title: 'Making things'
|
||||||
|
batch: 'B2'
|
||||||
|
status: 40 # COMPLETE
|
||||||
|
quantity: 21
|
||||||
|
notes: 'Some more simple notes'
|
||||||
|
creation_date: '2019-03-16'
|
@ -2,32 +2,35 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
|
from django.urls import reverse
|
||||||
|
from django.contrib.auth import get_user_model
|
||||||
|
|
||||||
|
from rest_framework.test import APITestCase
|
||||||
|
from rest_framework import status
|
||||||
|
|
||||||
|
import json
|
||||||
|
|
||||||
from .models import Build
|
from .models import Build
|
||||||
from part.models import Part
|
|
||||||
|
|
||||||
from InvenTree.status_codes import BuildStatus
|
from InvenTree.status_codes import BuildStatus
|
||||||
|
|
||||||
|
|
||||||
class BuildTestSimple(TestCase):
|
class BuildTestSimple(TestCase):
|
||||||
|
|
||||||
|
fixtures = [
|
||||||
|
'category',
|
||||||
|
'part',
|
||||||
|
'location',
|
||||||
|
'build',
|
||||||
|
]
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
part = Part.objects.create(name='Test part',
|
# Create a user for auth
|
||||||
description='Simple description')
|
User = get_user_model()
|
||||||
|
User.objects.create_user('testuser', 'test@testing.com', 'password')
|
||||||
|
|
||||||
Build.objects.create(part=part,
|
self.user = User.objects.get(username='testuser')
|
||||||
batch='B1',
|
self.client.login(username='testuser', password='password')
|
||||||
status=BuildStatus.PENDING,
|
|
||||||
title='Building 7 parts',
|
|
||||||
quantity=7,
|
|
||||||
notes='Some simple notes')
|
|
||||||
|
|
||||||
Build.objects.create(part=part,
|
|
||||||
batch='B2',
|
|
||||||
status=BuildStatus.COMPLETE,
|
|
||||||
title='Building 21 parts',
|
|
||||||
quantity=21,
|
|
||||||
notes='Some simple notes')
|
|
||||||
|
|
||||||
def test_build_objects(self):
|
def test_build_objects(self):
|
||||||
# Ensure the Build objects were correctly created
|
# Ensure the Build objects were correctly created
|
||||||
@ -36,7 +39,7 @@ class BuildTestSimple(TestCase):
|
|||||||
self.assertEqual(b.batch, 'B2')
|
self.assertEqual(b.batch, 'B2')
|
||||||
self.assertEqual(b.quantity, 21)
|
self.assertEqual(b.quantity, 21)
|
||||||
|
|
||||||
self.assertEqual(str(b), 'Build 21 x Test part - Simple description')
|
self.assertEqual(str(b), 'Build 21 x Orphan - A part without a category')
|
||||||
|
|
||||||
def test_url(self):
|
def test_url(self):
|
||||||
b1 = Build.objects.get(pk=1)
|
b1 = Build.objects.get(pk=1)
|
||||||
@ -62,13 +65,226 @@ class BuildTestSimple(TestCase):
|
|||||||
# TODO - Generate BOM for test part
|
# TODO - Generate BOM for test part
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def cancel_build(self):
|
def test_cancel_build(self):
|
||||||
""" Test build cancellation function """
|
""" Test build cancellation function """
|
||||||
|
|
||||||
build = Build.objects.get(id=1)
|
build = Build.objects.get(id=1)
|
||||||
|
|
||||||
self.assertEqual(build.status, BuildStatus.PENDING)
|
self.assertEqual(build.status, BuildStatus.PENDING)
|
||||||
|
|
||||||
build.cancelBuild()
|
build.cancelBuild(self.user)
|
||||||
|
|
||||||
self.assertEqual(build.status, BuildStatus.CANCELLED)
|
self.assertEqual(build.status, BuildStatus.CANCELLED)
|
||||||
|
|
||||||
|
|
||||||
|
class TestBuildAPI(APITestCase):
|
||||||
|
"""
|
||||||
|
Series of tests for the Build DRF API
|
||||||
|
- Tests for Build API
|
||||||
|
- Tests for BuildItem API
|
||||||
|
"""
|
||||||
|
|
||||||
|
fixtures = [
|
||||||
|
'category',
|
||||||
|
'part',
|
||||||
|
'location',
|
||||||
|
'build',
|
||||||
|
]
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
# Create a user for auth
|
||||||
|
User = get_user_model()
|
||||||
|
User.objects.create_user('testuser', 'test@testing.com', 'password')
|
||||||
|
|
||||||
|
self.client.login(username='testuser', password='password')
|
||||||
|
|
||||||
|
def test_get_build_list(self):
|
||||||
|
""" Test that we can retrieve list of build objects """
|
||||||
|
url = reverse('api-build-list')
|
||||||
|
response = self.client.get(url, format='json')
|
||||||
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
|
|
||||||
|
def test_get_build_item_list(self):
|
||||||
|
""" Test that we can retrieve list of BuildItem objects """
|
||||||
|
url = reverse('api-build-item-list')
|
||||||
|
|
||||||
|
response = self.client.get(url, format='json')
|
||||||
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
|
|
||||||
|
# Test again, filtering by park ID
|
||||||
|
response = self.client.get(url, {'part': '1'}, format='json')
|
||||||
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
|
|
||||||
|
|
||||||
|
class TestBuildViews(TestCase):
|
||||||
|
""" Tests for Build app views """
|
||||||
|
|
||||||
|
fixtures = [
|
||||||
|
'category',
|
||||||
|
'part',
|
||||||
|
'location',
|
||||||
|
'build',
|
||||||
|
]
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super().setUp()
|
||||||
|
|
||||||
|
# Create a user
|
||||||
|
User = get_user_model()
|
||||||
|
User.objects.create_user('username', 'user@email.com', 'password')
|
||||||
|
|
||||||
|
self.client.login(username='username', password='password')
|
||||||
|
|
||||||
|
def test_build_index(self):
|
||||||
|
""" test build index view """
|
||||||
|
|
||||||
|
response = self.client.get(reverse('build-index'))
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
content = str(response.content)
|
||||||
|
|
||||||
|
# Content should contain build titles
|
||||||
|
for build in Build.objects.all():
|
||||||
|
self.assertIn(build.title, content)
|
||||||
|
|
||||||
|
def test_build_detail(self):
|
||||||
|
""" Test the detail view for a Build object """
|
||||||
|
|
||||||
|
pk = 1
|
||||||
|
|
||||||
|
response = self.client.get(reverse('build-detail', args=(pk,)))
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
build = Build.objects.get(pk=pk)
|
||||||
|
|
||||||
|
content = str(response.content)
|
||||||
|
|
||||||
|
self.assertIn(build.title, content)
|
||||||
|
|
||||||
|
def test_build_create(self):
|
||||||
|
""" Test the build creation view (ajax form) """
|
||||||
|
|
||||||
|
url = reverse('build-create')
|
||||||
|
|
||||||
|
# Create build without specifying part
|
||||||
|
response = self.client.get(url, HTTP_X_REQUESTED_WITH='XMLHttpRequest')
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
# Create build with valid part
|
||||||
|
response = self.client.get(url, {'part': 1}, HTTP_X_REQUESTED_WITH='XMLHttpRequest')
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
# Create build with invalid part
|
||||||
|
response = self.client.get(url, {'part': 9999}, HTTP_X_REQUESTED_WITH='XMLHttpRequest')
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
def test_build_allocate(self):
|
||||||
|
""" Test the part allocation view for a Build """
|
||||||
|
|
||||||
|
url = reverse('build-allocate', args=(1,))
|
||||||
|
|
||||||
|
# Get the page normally
|
||||||
|
response = self.client.get(url)
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
# Get the page in editing mode
|
||||||
|
response = self.client.get(url, {'edit': 1})
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
def test_build_item_create(self):
|
||||||
|
""" Test the BuildItem creation view (ajax form) """
|
||||||
|
|
||||||
|
url = reverse('build-item-create')
|
||||||
|
|
||||||
|
# Try without a part specified
|
||||||
|
response = self.client.get(url, {'build': 1}, HTTP_X_REQUESTED_WITH='XMLHttpRequest')
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
# Try with an invalid build ID
|
||||||
|
response = self.client.get(url, {'build': 9999}, HTTP_X_REQUESTED_WITH='XMLHttpRequest')
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
# Try with a valid part specified
|
||||||
|
response = self.client.get(url, {'build': 1, 'part': 1}, HTTP_X_REQUESTED_WITH='XMLHttpRequest')
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
# Try with an invalid part specified
|
||||||
|
response = self.client.get(url, {'build': 1, 'part': 9999}, HTTP_X_REQUESTED_WITH='XMLHttpRequest')
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
def test_build_item_edit(self):
|
||||||
|
""" Test the BuildItem edit view (ajax form) """
|
||||||
|
|
||||||
|
# TODO
|
||||||
|
# url = reverse('build-item-edit')
|
||||||
|
pass
|
||||||
|
|
||||||
|
def test_build_complete(self):
|
||||||
|
""" Test the build completion form """
|
||||||
|
|
||||||
|
url = reverse('build-complete', args=(1,))
|
||||||
|
|
||||||
|
# Test without confirmation
|
||||||
|
response = self.client.post(url, HTTP_X_REQUESTED_WITH='XMLHttpRequest')
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
data = json.loads(response.content)
|
||||||
|
self.assertFalse(data['form_valid'])
|
||||||
|
|
||||||
|
# Test with confirmation, valid location
|
||||||
|
response = self.client.post(url, {'confirm': 1, 'location': 1}, HTTP_X_REQUESTED_WITH='XMLHttpRequest')
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
data = json.loads(response.content)
|
||||||
|
self.assertTrue(data['form_valid'])
|
||||||
|
|
||||||
|
# Test with confirmation, invalid location
|
||||||
|
response = self.client.post(url, {'confirm': 1, 'location': 9999}, HTTP_X_REQUESTED_WITH='XMLHttpRequest')
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
data = json.loads(response.content)
|
||||||
|
self.assertFalse(data['form_valid'])
|
||||||
|
|
||||||
|
def test_build_cancel(self):
|
||||||
|
""" Test the build cancellation form """
|
||||||
|
|
||||||
|
url = reverse('build-cancel', args=(1,))
|
||||||
|
|
||||||
|
# Test without confirmation
|
||||||
|
response = self.client.post(url, HTTP_X_REQUESTED_WITH='XMLHttpRequest')
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
data = json.loads(response.content)
|
||||||
|
self.assertFalse(data['form_valid'])
|
||||||
|
|
||||||
|
b = Build.objects.get(pk=1)
|
||||||
|
self.assertEqual(b.status, 10) # Build status is still PENDING
|
||||||
|
|
||||||
|
# Test with confirmation
|
||||||
|
response = self.client.post(url, {'confirm_cancel': 1}, HTTP_X_REQUESTED_WITH='XMLHttpRequest')
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
data = json.loads(response.content)
|
||||||
|
self.assertTrue(data['form_valid'])
|
||||||
|
|
||||||
|
b = Build.objects.get(pk=1)
|
||||||
|
self.assertEqual(b.status, 30) # Build status is now CANCELLED
|
||||||
|
|
||||||
|
def test_build_unallocate(self):
|
||||||
|
""" Test the build unallocation view (ajax form) """
|
||||||
|
|
||||||
|
url = reverse('build-unallocate', args=(1,))
|
||||||
|
|
||||||
|
# Test without confirmation
|
||||||
|
response = self.client.post(url, HTTP_X_REQUESTED_WITH='XMLHttpRequest')
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
data = json.loads(response.content)
|
||||||
|
self.assertFalse(data['form_valid'])
|
||||||
|
|
||||||
|
# Test with confirmation
|
||||||
|
response = self.client.post(url, {'confirm': 1}, HTTP_X_REQUESTED_WITH='XMLHttpRequest')
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
data = json.loads(response.content)
|
||||||
|
self.assertTrue(data['form_valid'])
|
||||||
|
@ -518,6 +518,8 @@ class BuildItemCreate(AjaxCreateView):
|
|||||||
part = Part.objects.get(pk=part_id)
|
part = Part.objects.get(pk=part_id)
|
||||||
except Part.DoesNotExist:
|
except Part.DoesNotExist:
|
||||||
part = None
|
part = None
|
||||||
|
else:
|
||||||
|
part = None
|
||||||
|
|
||||||
if build_id:
|
if build_id:
|
||||||
try:
|
try:
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![Build Status](https://travis-ci.org/inventree/InvenTree.svg?branch=master)](https://travis-ci.org/inventree/InvenTree) [![Documentation Status](https://readthedocs.org/projects/inventree/badge/?version=latest)](https://inventree.readthedocs.io/en/latest/?badge=latest) [![Coverage Status](https://coveralls.io/repos/github/inventree/InvenTree/badge.svg)](https://coveralls.io/github/inventree/InvenTree)
|
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![Build Status](https://travis-ci.org/inventree/InvenTree.svg?branch=master)](https://travis-ci.org/inventree/InvenTree) [![Documentation Status](https://readthedocs.org/projects/inventree/badge/?version=latest)](https://inventree.readthedocs.io/en/latest/?badge=latest) [![Coverage Status](https://coveralls.io/repos/github/inventree/InvenTree/badge.svg)](https://coveralls.io/github/inventree/InvenTree)
|
||||||
|
|
||||||
|
<img src="images/logo/inventree.png" alt="InvenTree" width="128"/>
|
||||||
|
|
||||||
# InvenTree
|
# InvenTree
|
||||||
InvenTree is an open-source Inventory Management System which provides powerful low-level stock control and part tracking. The core of the InvenTree system is a Python/Django database backend which provides an admin interface (web-based) and a JSON API for interaction with external interfaces and applications.
|
InvenTree is an open-source Inventory Management System which provides powerful low-level stock control and part tracking. The core of the InvenTree system is a Python/Django database backend which provides an admin interface (web-based) and a JSON API for interaction with external interfaces and applications.
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user