def test_create_stock_with_expiry(self): """ Test creation of stock item of a part with an expiry date. The initial value for the "expiry_date" field should be pre-filled, and should be in the future! """ # First, ensure that the expiry date feature is enabled! InvenTreeSetting.set_setting('STOCK_ENABLE_EXPIRY', True, self.user) url = reverse('stock-item-create') response = self.client.get(url, {'part': 25}, HTTP_X_REQUESTED_WITH='XMLHttpRequest') self.assertEqual(response.status_code, 200) # We are expecting 10 days in the future expiry = datetime.now().date() + timedelta(10) expected = f'name=\\\\"expiry_date\\\\" value=\\\\"{expiry.isoformat()}\\\\"' self.assertIn(expected, str(response.content)) # Now check with a part which does *not* have a default expiry period response = self.client.get(url, {'part': 1}, HTTP_X_REQUESTED_WITH='XMLHttpRequest') expected = 'name=\\\\"expiry_date\\\\" placeholder=\\\\"\\\\"' self.assertIn(expected, str(response.content))
def enable_ownership(self): # Enable stock location ownership InvenTreeSetting.set_setting('STOCK_OWNERSHIP_CONTROL', True, self.user) self.assertEqual( True, InvenTreeSetting.get_setting('STOCK_OWNERSHIP_CONTROL'))
def test_default_shipment(self): """Test sales order default shipment creation""" # Default setting value should be False self.assertEqual( False, InvenTreeSetting.get_setting('SALESORDER_DEFAULT_SHIPMENT')) # Create an order order_1 = SalesOrder.objects.create(customer=self.customer, reference='1235', customer_reference='ABC 55556') # Order should have no shipments when setting is False self.assertEqual(0, order_1.shipment_count) # Update setting to True InvenTreeSetting.set_setting('SALESORDER_DEFAULT_SHIPMENT', True, None) self.assertEqual( True, InvenTreeSetting.get_setting('SALESORDER_DEFAULT_SHIPMENT')) # Create a second order order_2 = SalesOrder.objects.create(customer=self.customer, reference='1236', customer_reference='ABC 55557') # Order should have one shipment self.assertEqual(1, order_2.shipment_count) self.assertEqual(1, order_2.pending_shipments().count()) # Shipment should have default reference of '1' self.assertEqual('1', order_2.pending_shipments()[0].reference)
def test_duplicate_ipn(self): """ Test the setting which controls duplicate IPN values """ # Create a part Part.objects.create(name='Hello', description='A thing', IPN='IPN123', revision='A') # Attempt to create a duplicate item (should fail) with self.assertRaises(ValidationError): part = Part(name='Hello', description='A thing', IPN='IPN123', revision='A') part.validate_unique() # Attempt to create item with duplicate IPN (should be allowed by default) Part.objects.create(name='Hello', description='A thing', IPN='IPN123', revision='B') # And attempt again with the same values (should fail) with self.assertRaises(ValidationError): part = Part(name='Hello', description='A thing', IPN='IPN123', revision='B') part.validate_unique() # Now update the settings so duplicate IPN values are *not* allowed InvenTreeSetting.set_setting('PART_ALLOW_DUPLICATE_IPN', False, self.user) with self.assertRaises(ValidationError): part = Part(name='Hello', description='A thing', IPN='IPN123', revision='C') part.full_clean()
def test_printing_process(self): """Test that a label can be printed.""" # Ensure the labels were created apps.get_app_config('label').create_labels() # Lookup references part = Part.objects.first() plugin_ref = 'samplelabel' label = PartLabel.objects.first() url = self.do_url([part], plugin_ref, label) # Non-exsisting plugin response = self.get(f'{url}123', expected_code=404) self.assertIn(f'Plugin \'{plugin_ref}123\' not found', str(response.content, 'utf8')) # Inactive plugin response = self.get(url, expected_code=400) self.assertIn(f'Plugin \'{plugin_ref}\' is not enabled', str(response.content, 'utf8')) # Active plugin self.do_activate_plugin() # Print one part self.get(url, expected_code=200) # Print multiple parts self.get(self.do_url(Part.objects.all()[:2], plugin_ref, label), expected_code=200) # Print multiple parts without a plugin self.get(self.do_url(Part.objects.all()[:2], None, label), expected_code=200) # Print multiple parts without a plugin in debug mode InvenTreeSetting.set_setting('REPORT_DEBUG_MODE', True, None) response = self.get(self.do_url(Part.objects.all()[:2], None, label), expected_code=200) self.assertIn('@page', str(response.content)) # Print no part self.get(self.do_url(None, plugin_ref, label), expected_code=400) # Test that the labels have been printed # The sample labelling plugin simply prints to file self.assertTrue(os.path.exists('label.pdf')) # Read the raw .pdf data - ensure it contains some sensible information with open('label.pdf', 'rb') as f: pdf_data = str(f.read()) self.assertIn('WeasyPrint', pdf_data) # Check that the .png file has already been created self.assertTrue(os.path.exists('label.png')) # And that it is a valid image file Image.open('label.png')
def test_instance_url(self): """Test instance url settings.""" # Set up required setting InvenTreeSetting.set_setting("INVENTREE_BASE_URL", "http://127.1.2.3", self.user) # The site should also be changed site_obj = Site.objects.all().order_by('id').first() self.assertEqual(site_obj.domain, 'http://127.1.2.3')
def test_instance_name(self): # default setting self.assertEqual(version.inventreeInstanceTitle(), 'InvenTree') # set up required setting InvenTreeSetting.set_setting("INVENTREE_INSTANCE_TITLE", True, self.user) InvenTreeSetting.set_setting("INVENTREE_INSTANCE", "Testing title", self.user) self.assertEqual(version.inventreeInstanceTitle(), 'Testing title')
def set_default_currency(apps, schema_editor): """ migrate the currency setting from config.yml to db """ # get value from settings-file base_currency = get_setting('INVENTREE_BASE_CURRENCY', CONFIG.get('base_currency', 'USD')) # write to database InvenTreeSetting.set_setting('INVENTREE_DEFAULT_CURRENCY', base_currency, None, create=True)
def test_default_values(self): """ Tests for 'default' values: Ensure that unspecified fields revert to "default" values (as specified in the model field definition) """ url = reverse('api-part-list') response = self.client.post(url, { 'name': 'all defaults', 'description': 'my test part', 'category': 1, }) data = response.data # Check that the un-specified fields have used correct default values self.assertTrue(data['active']) self.assertFalse(data['virtual']) # By default, parts are purchaseable self.assertTrue(data['purchaseable']) # Set the default 'purchaseable' status to True InvenTreeSetting.set_setting( 'PART_PURCHASEABLE', True, self.user ) response = self.client.post(url, { 'name': 'all defaults', 'description': 'my test part 2', 'category': 1, }) # Part should now be purchaseable by default self.assertTrue(response.data['purchaseable']) # "default" values should not be used if the value is specified response = self.client.post(url, { 'name': 'all defaults', 'description': 'my test part 2', 'category': 1, 'active': False, 'purchaseable': False, }) self.assertFalse(response.data['active']) self.assertFalse(response.data['purchaseable'])
def test_custom(self): """ Update some of the part values and re-test """ for val in [True, False]: InvenTreeSetting.set_setting('PART_COMPONENT', val, self.user) InvenTreeSetting.set_setting('PART_PURCHASEABLE', val, self.user) InvenTreeSetting.set_setting('PART_SALABLE', val, self.user) InvenTreeSetting.set_setting('PART_TRACKABLE', val, self.user) self.assertEqual(val, InvenTreeSetting.get_setting('PART_COMPONENT')) self.assertEqual(val, InvenTreeSetting.get_setting('PART_PURCHASEABLE')) self.assertEqual(val, InvenTreeSetting.get_setting('PART_SALABLE')) self.assertEqual(val, InvenTreeSetting.get_setting('PART_TRACKABLE')) part = self.make_part() self.assertEqual(part.component, val) self.assertEqual(part.purchaseable, val) self.assertEqual(part.salable, val) self.assertEqual(part.trackable, val) Part.objects.filter(pk=part.pk).delete()
def test_initial_install(self): """Test if install of plugins on startup works""" from plugin import registry # Check an install run response = registry.install_plugin_file() self.assertEqual(response, 'first_run') # Set dynamic setting to True and rerun to launch install InvenTreeSetting.set_setting('PLUGIN_ON_STARTUP', True, self.user) registry.reload_plugins() # Check that there was anotehr run response = registry.install_plugin_file() self.assertEqual(response, True)
def set_globalsetting(self, key, value, user): """ set plugin global setting by key """ from common.models import InvenTreeSetting return InvenTreeSetting.set_setting(self._globalsetting_name(key), value, user)
def test_instance_name(self): """Test instance name settings.""" # default setting self.assertEqual(version.inventreeInstanceTitle(), 'InvenTree') # set up required setting InvenTreeSetting.set_setting("INVENTREE_INSTANCE_TITLE", True, self.user) InvenTreeSetting.set_setting("INVENTREE_INSTANCE", "Testing title", self.user) self.assertEqual(version.inventreeInstanceTitle(), 'Testing title') # The site should also be changed site_obj = Site.objects.all().order_by('id').first() self.assertEqual(site_obj.name, 'Testing title')
def test_filter_by_expired(self): """ Filter StockItem by expiry status """ # First, we can assume that the 'stock expiry' feature is disabled response = self.get_stock(expired=1) self.assertEqual(len(response), 20) self.user.is_staff = True self.user.save() # Now, ensure that the expiry date feature is enabled! InvenTreeSetting.set_setting('STOCK_ENABLE_EXPIRY', True, self.user) response = self.get_stock(expired=1) self.assertEqual(len(response), 1) for item in response: self.assertTrue(item['expired']) response = self.get_stock(expired=0) self.assertEqual(len(response), 19) for item in response: self.assertFalse(item['expired']) # Mark some other stock items as expired today = datetime.now().date() for pk in [510, 511, 512]: item = StockItem.objects.get(pk=pk) item.expiry_date = today - timedelta(days=pk) item.save() response = self.get_stock(expired=1) self.assertEqual(len(response), 4) response = self.get_stock(expired=0) self.assertEqual(len(response), 16)
def test_printing_process(self): """Test that a label can be printed""" # Ensure the labels were created apps.get_app_config('label').create_labels() # Lookup references part = Part.objects.first() plugin_ref = 'samplelabel' label = PartLabel.objects.first() url = self.do_url([part], plugin_ref, label) # Non-exsisting plugin response = self.get(f'{url}123', expected_code=404) self.assertIn(f'Plugin \'{plugin_ref}123\' not found', str(response.content, 'utf8')) # Inactive plugin response = self.get(url, expected_code=400) self.assertIn(f'Plugin \'{plugin_ref}\' is not enabled', str(response.content, 'utf8')) # Active plugin self.do_activate_plugin() # Print one part self.get(url, expected_code=200) # Print multiple parts self.get(self.do_url(Part.objects.all()[:2], plugin_ref, label), expected_code=200) # Print multiple parts without a plugin self.get(self.do_url(Part.objects.all()[:2], None, label), expected_code=200) # Print multiple parts without a plugin in debug mode InvenTreeSetting.set_setting('REPORT_DEBUG_MODE', True, None) response = self.get(self.do_url(Part.objects.all()[:2], None, label), expected_code=200) self.assertIn('@page', str(response.content)) # Print no part self.get(self.do_url(None, plugin_ref, label), expected_code=400)
def test_print(self): """Printing tests for the TestReport.""" report = self.model.objects.first() url = reverse(self.print_url, kwargs={'pk': report.pk}) # Try to print without providing a valid StockItem response = self.get(url, expected_code=400) # Try to print with an invalid StockItem response = self.get(url, {'item': 9999}, expected_code=400) # Now print with a valid StockItem item = StockItem.objects.first() response = self.get(url, {'item': item.pk}, expected_code=200) # Response should be a StreamingHttpResponse (PDF file) self.assertEqual(type(response), StreamingHttpResponse) headers = response.headers self.assertEqual(headers['Content-Type'], 'application/pdf') # By default, this should *not* have created an attachment against this stockitem self.assertFalse( StockItemAttachment.objects.filter(stock_item=item).exists()) # Change the setting, now the test report should be attached automatically InvenTreeSetting.set_setting('REPORT_ATTACH_TEST_REPORT', True, None) response = self.get(url, {'item': item.pk}, expected_code=200) headers = response.headers self.assertEqual(headers['Content-Type'], 'application/pdf') # Check that a report has been uploaded attachment = StockItemAttachment.objects.filter( stock_item=item).first() self.assertIsNotNone(attachment)
def debug_mode(self, value: bool): """Enable or disable debug mode for reports""" InvenTreeSetting.set_setting('REPORT_DEBUG_MODE', value, change_user=None)
def test_duplicate_ipn(self): """Test the setting which controls duplicate IPN values.""" # Create a part Part.objects.create(name='Hello', description='A thing', IPN='IPN123', revision='A') # Attempt to create a duplicate item (should fail) with self.assertRaises(ValidationError): part = Part(name='Hello', description='A thing', IPN='IPN123', revision='A') part.validate_unique() # Attempt to create item with duplicate IPN (should be allowed by default) Part.objects.create(name='Hello', description='A thing', IPN='IPN123', revision='B') # And attempt again with the same values (should fail) with self.assertRaises(ValidationError): part = Part(name='Hello', description='A thing', IPN='IPN123', revision='B') part.validate_unique() # Now update the settings so duplicate IPN values are *not* allowed InvenTreeSetting.set_setting('PART_ALLOW_DUPLICATE_IPN', False, self.user) with self.assertRaises(ValidationError): part = Part(name='Hello', description='A thing', IPN='IPN123', revision='C') part.full_clean() # Any duplicate IPN should raise an error Part.objects.create(name='xyz', revision='1', description='A part', IPN='UNIQUE') # Case insensitive, so variations on spelling should throw an error for ipn in ['UNiquE', 'uniQuE', 'unique']: with self.assertRaises(ValidationError): Part.objects.create(name='xyz', revision='2', description='A part', IPN=ipn) with self.assertRaises(ValidationError): Part.objects.create(name='zyx', description='A part', IPN='UNIQUE') # However, *blank* / empty IPN values should be allowed, even if duplicates are not # Note that leading / trailling whitespace characters are trimmed, too Part.objects.create(name='abc', revision='1', description='A part', IPN=None) Part.objects.create(name='abc', revision='2', description='A part', IPN='') Part.objects.create(name='abc', revision='3', description='A part', IPN=None) Part.objects.create(name='abc', revision='4', description='A part', IPN=' ') Part.objects.create(name='abc', revision='5', description='A part', IPN=' ') Part.objects.create(name='abc', revision='6', description='A part', IPN=' ')