mirror of
				https://github.com/inventree/InvenTree.git
				synced 2025-10-31 13:15:43 +00:00 
			
		
		
		
	Refactor template helpers for displaying uploaded images (#3377)
* Refactor template helpers for displaying uploaded images * Unit test for asset tag * Unit tests for 'uploaded_image' tag * Add simple tests for part_image and company_image functions * Unit test for barcode constructor * Unit tests for qrcode * Refactor the 'company_logo.png' to be a new template tag - Add unit tests * Adds a new field to the report asset model - Unique key which can be used to identify particular assets - e.g. company logo * Refactor logo image tags - Make use of existing CUSTOM_LOGO setting - Adds a "logo_image" template tag for reports * Remove previous migration - strategy no longer required
This commit is contained in:
		| @@ -2,13 +2,16 @@ | ||||
|  | ||||
| import io | ||||
| import json | ||||
| import logging | ||||
| import os.path | ||||
| import re | ||||
| from decimal import Decimal, InvalidOperation | ||||
| from wsgiref.util import FileWrapper | ||||
|  | ||||
| from django.conf import settings | ||||
| from django.contrib.auth.models import Permission | ||||
| from django.core.exceptions import FieldError, ValidationError | ||||
| from django.core.files.storage import default_storage | ||||
| from django.http import StreamingHttpResponse | ||||
| from django.test import TestCase | ||||
| from django.utils.translation import gettext_lazy as _ | ||||
| @@ -25,6 +28,8 @@ from common.settings import currency_code_default | ||||
| from .api_tester import UserMixin | ||||
| from .settings import MEDIA_URL, STATIC_URL | ||||
|  | ||||
| logger = logging.getLogger('inventree') | ||||
|  | ||||
|  | ||||
| def getSetting(key, backup_value=None): | ||||
|     """Shortcut for reading a setting value from the database.""" | ||||
| @@ -82,6 +87,15 @@ def construct_absolute_url(*arg): | ||||
|     return url | ||||
|  | ||||
|  | ||||
| def TestIfImage(img): | ||||
|     """Test if an image file is indeed an image.""" | ||||
|     try: | ||||
|         Image.open(img).verify() | ||||
|         return True | ||||
|     except Exception: | ||||
|         return False | ||||
|  | ||||
|  | ||||
| def getBlankImage(): | ||||
|     """Return the qualified path for the 'blank image' placeholder.""" | ||||
|     return getStaticUrl("img/blank_image.png") | ||||
| @@ -92,13 +106,23 @@ def getBlankThumbnail(): | ||||
|     return getStaticUrl("img/blank_image.thumbnail.png") | ||||
|  | ||||
|  | ||||
| def TestIfImage(img): | ||||
|     """Test if an image file is indeed an image.""" | ||||
|     try: | ||||
|         Image.open(img).verify() | ||||
|         return True | ||||
|     except Exception: | ||||
|         return False | ||||
| def getLogoImage(as_file=False): | ||||
|     """Return the InvenTree logo image, or a custom logo if available.""" | ||||
|  | ||||
|     """Return the path to the logo-file.""" | ||||
|     if settings.CUSTOM_LOGO: | ||||
|  | ||||
|         if as_file: | ||||
|             return f"file://{default_storage.path(settings.CUSTOM_LOGO)}" | ||||
|         else: | ||||
|             return default_storage.url(settings.CUSTOM_LOGO) | ||||
|  | ||||
|     else: | ||||
|         if as_file: | ||||
|             path = os.path.join(settings.STATIC_ROOT, 'img/inventree.png') | ||||
|             return f"file://{path}" | ||||
|         else: | ||||
|             return getStaticUrl('img/inventree.png') | ||||
|  | ||||
|  | ||||
| def TestIfImageURL(url): | ||||
|   | ||||
| @@ -967,5 +967,5 @@ CUSTOM_LOGO = get_setting( | ||||
|  | ||||
| # check that the logo-file exsists in media | ||||
| if CUSTOM_LOGO and not default_storage.exists(CUSTOM_LOGO):  # pragma: no cover | ||||
|     logger.warning(f"The custom logo file '{CUSTOM_LOGO}' could not be found in the default media storage") | ||||
|     CUSTOM_LOGO = False | ||||
|     logger.warning("The custom logo file could not be found in the default media storage") | ||||
|   | ||||
| @@ -240,6 +240,17 @@ class TestHelpers(TestCase): | ||||
|         self.assertEqual(helpers.decimal2string(Decimal('1.2345000')), '1.2345') | ||||
|         self.assertEqual(helpers.decimal2string('test'), 'test') | ||||
|  | ||||
|     def test_logo_image(self): | ||||
|         """Test for retrieving logo image""" | ||||
|  | ||||
|         # By default, there is no custom logo provided | ||||
|  | ||||
|         logo = helpers.getLogoImage() | ||||
|         self.assertEqual(logo, '/static/img/inventree.png') | ||||
|  | ||||
|         logo = helpers.getLogoImage(as_file=True) | ||||
|         self.assertEqual(logo, f'file://{settings.STATIC_ROOT}/img/inventree.png') | ||||
|  | ||||
|  | ||||
| class TestQuoteWrap(TestCase): | ||||
|     """Tests for string wrapping.""" | ||||
|   | ||||
| @@ -17,10 +17,10 @@ from stdimage.models import StdImageField | ||||
| import common.models | ||||
| import common.settings | ||||
| import InvenTree.fields | ||||
| import InvenTree.helpers | ||||
| import InvenTree.validators | ||||
| from common.settings import currency_code_default | ||||
| from InvenTree.fields import InvenTreeURLField | ||||
| from InvenTree.helpers import getBlankImage, getBlankThumbnail, getMediaUrl | ||||
| from InvenTree.models import InvenTreeAttachment | ||||
| from InvenTree.status_codes import PurchaseOrderStatus | ||||
|  | ||||
| @@ -177,16 +177,16 @@ class Company(models.Model): | ||||
|     def get_image_url(self): | ||||
|         """Return the URL of the image for this company.""" | ||||
|         if self.image: | ||||
|             return getMediaUrl(self.image.url) | ||||
|             return InvenTree.helpers.getMediaUrl(self.image.url) | ||||
|         else: | ||||
|             return getBlankImage() | ||||
|             return InvenTree.helpers.getBlankImage() | ||||
|  | ||||
|     def get_thumbnail_url(self): | ||||
|         """Return the URL for the thumbnail image for this Company.""" | ||||
|         if self.image: | ||||
|             return getMediaUrl(self.image.thumbnail.url) | ||||
|             return InvenTree.helpers.getMediaUrl(self.image.thumbnail.url) | ||||
|         else: | ||||
|             return getBlankThumbnail() | ||||
|             return InvenTree.helpers.getBlankThumbnail() | ||||
|  | ||||
|     @property | ||||
|     def parts(self): | ||||
|   | ||||
| @@ -7,8 +7,7 @@ from datetime import date, datetime | ||||
|  | ||||
| from django import template | ||||
| from django.conf import settings as djangosettings | ||||
| from django.core.files.storage import default_storage | ||||
| from django.templatetags.static import StaticNode, static | ||||
| from django.templatetags.static import StaticNode | ||||
| from django.urls import reverse | ||||
| from django.utils.html import format_html | ||||
| from django.utils.safestring import mark_safe | ||||
| @@ -174,6 +173,16 @@ def inventree_title(*args, **kwargs): | ||||
|     return version.inventreeInstanceTitle() | ||||
|  | ||||
|  | ||||
| @register.simple_tag() | ||||
| def inventree_logo(**kwargs): | ||||
|     """Return the InvenTree logo, *or* a custom logo if the user has uploaded one. | ||||
|  | ||||
|     Returns a path to an image file, which can be rendered in the web interface | ||||
|     """ | ||||
|  | ||||
|     return InvenTree.helpers.getLogoImage(**kwargs) | ||||
|  | ||||
|  | ||||
| @register.simple_tag() | ||||
| def inventree_base_url(*args, **kwargs): | ||||
|     """Return the INVENTREE_BASE_URL setting.""" | ||||
| @@ -473,14 +482,6 @@ def inventree_customize(reference, *args, **kwargs): | ||||
|     return djangosettings.CUSTOMIZE.get(reference, '') | ||||
|  | ||||
|  | ||||
| @register.simple_tag() | ||||
| def inventree_logo(*args, **kwargs): | ||||
|     """Return the path to the logo-file.""" | ||||
|     if settings.CUSTOM_LOGO: | ||||
|         return default_storage.url(settings.CUSTOM_LOGO) | ||||
|     return static('img/inventree.png') | ||||
|  | ||||
|  | ||||
| class I18nStaticNode(StaticNode): | ||||
|     """Custom StaticNode. | ||||
|  | ||||
|   | ||||
| @@ -535,14 +535,23 @@ class ReportAsset(models.Model): | ||||
|     and can be loaded in a template using the {% report_asset <filename> %} tag. | ||||
|     """ | ||||
|  | ||||
|     # String keys used for uniquely indentifying particular assets | ||||
|     ASSET_COMPANY_LOGO = "COMPANY_LOGO" | ||||
|  | ||||
|     def __str__(self): | ||||
|         """String representation of a ReportAsset instance""" | ||||
|         return os.path.basename(self.asset.name) | ||||
|  | ||||
|     # Asset file | ||||
|     asset = models.FileField( | ||||
|         upload_to=rename_asset, | ||||
|         verbose_name=_('Asset'), | ||||
|         help_text=_("Report asset file"), | ||||
|     ) | ||||
|  | ||||
|     description = models.CharField(max_length=250, verbose_name=_('Description'), help_text=_("Asset file description")) | ||||
|     # Asset description (user facing string, not used internally) | ||||
|     description = models.CharField( | ||||
|         max_length=250, | ||||
|         verbose_name=_('Description'), | ||||
|         help_text=_("Asset file description") | ||||
|     ) | ||||
|   | ||||
| @@ -78,8 +78,7 @@ content: "v{{report_revision}} - {{ date.isoformat }}"; | ||||
| {% endblock %} | ||||
|  | ||||
| {% block header_content %} | ||||
|     <!-- TODO - Make the company logo asset generic --> | ||||
|     <img class='logo' src="{% asset 'company_logo.png' %}" alt="logo" width="150"> | ||||
|     <img class='logo' src="{% logo_image %}" alt="logo" width="150"> | ||||
|  | ||||
|     <div class='header-right'> | ||||
|         <h3> | ||||
|   | ||||
| @@ -28,21 +28,29 @@ def image_data(img, fmt='PNG'): | ||||
| def qrcode(data, **kwargs): | ||||
|     """Return a byte-encoded QR code image. | ||||
|  | ||||
|     Optional kwargs | ||||
|     --------------- | ||||
|  | ||||
|     kwargs: | ||||
|         fill_color: Fill color (default = black) | ||||
|         back_color: Background color (default = white) | ||||
|         version: Default = 1 | ||||
|         box_size: Default = 20 | ||||
|         border: Default = 1 | ||||
|  | ||||
|     Returns: | ||||
|         base64 encoded image data | ||||
|  | ||||
|     """ | ||||
|     # Construct "default" values | ||||
|     params = dict( | ||||
|         box_size=20, | ||||
|         border=1, | ||||
|         version=1, | ||||
|     ) | ||||
|  | ||||
|     fill_color = kwargs.pop('fill_color', 'black') | ||||
|     back_color = kwargs.pop('back_color', 'white') | ||||
|  | ||||
|     format = kwargs.pop('format', 'PNG') | ||||
|  | ||||
|     params.update(**kwargs) | ||||
|  | ||||
|     qr = python_qrcode.QRCode(**params) | ||||
| @@ -50,9 +58,13 @@ def qrcode(data, **kwargs): | ||||
|     qr.add_data(data, optimize=20) | ||||
|     qr.make(fit=True) | ||||
|  | ||||
|     qri = qr.make_image(fill_color=fill_color, back_color=back_color) | ||||
|     qri = qr.make_image( | ||||
|         fill_color=fill_color, | ||||
|         back_color=back_color | ||||
|     ) | ||||
|  | ||||
|     return image_data(qri) | ||||
|     # Render to byte-encoded image | ||||
|     return image_data(qri, fmt=format) | ||||
|  | ||||
|  | ||||
| @register.simple_tag() | ||||
| @@ -60,6 +72,8 @@ def barcode(data, barcode_class='code128', **kwargs): | ||||
|     """Render a barcode.""" | ||||
|     constructor = python_barcode.get_barcode_class(barcode_class) | ||||
|  | ||||
|     format = kwargs.pop('format', 'PNG') | ||||
|  | ||||
|     data = str(data).zfill(constructor.digits) | ||||
|  | ||||
|     writer = python_barcode.writer.ImageWriter | ||||
| @@ -68,5 +82,5 @@ def barcode(data, barcode_class='code128', **kwargs): | ||||
|  | ||||
|     image = barcode_image.render(writer_options=kwargs) | ||||
|  | ||||
|     # Render to byte-encoded PNG | ||||
|     return image_data(image) | ||||
|     # Render to byte-encoded image | ||||
|     return image_data(image, fmt=format) | ||||
|   | ||||
| @@ -10,22 +10,77 @@ import InvenTree.helpers | ||||
| from common.models import InvenTreeSetting | ||||
| from company.models import Company | ||||
| from part.models import Part | ||||
| from stock.models import StockItem | ||||
|  | ||||
| register = template.Library() | ||||
|  | ||||
|  | ||||
| @register.simple_tag() | ||||
| def asset(filename): | ||||
|     """Return fully-qualified path for an upload report asset file.""" | ||||
|     """Return fully-qualified path for an upload report asset file. | ||||
|  | ||||
|     Arguments: | ||||
|         filename: Asset filename (relative to the 'assets' media directory) | ||||
|  | ||||
|     Raises: | ||||
|         FileNotFoundError if file does not exist | ||||
|     """ | ||||
|     # If in debug mode, return URL to the image, not a local file | ||||
|     debug_mode = InvenTreeSetting.get_setting('REPORT_DEBUG_MODE') | ||||
|  | ||||
|     if debug_mode: | ||||
|         path = os.path.join(settings.MEDIA_URL, 'report', 'assets', filename) | ||||
|     else: | ||||
|     # Test if the file actually exists | ||||
|     full_path = os.path.join(settings.MEDIA_ROOT, 'report', 'assets', filename) | ||||
|  | ||||
|         path = os.path.join(settings.MEDIA_ROOT, 'report', 'assets', filename) | ||||
|     if not os.path.exists(full_path) or not os.path.isfile(full_path): | ||||
|         raise FileNotFoundError(f"Asset file '{filename}' does not exist") | ||||
|  | ||||
|     if debug_mode: | ||||
|         return os.path.join(settings.MEDIA_URL, 'report', 'assets', filename) | ||||
|     else: | ||||
|         return f"file://{full_path}" | ||||
|  | ||||
|  | ||||
| @register.simple_tag() | ||||
| def uploaded_image(filename, replace_missing=True, replacement_file='blank_image.png'): | ||||
|     """Return a fully-qualified path for an 'uploaded' image. | ||||
|  | ||||
|     Arguments: | ||||
|         filename: The filename of the image relative to the MEDIA_ROOT directory | ||||
|         replace_missing: Optionally return a placeholder image if the provided filename does not exist | ||||
|  | ||||
|     Returns: | ||||
|         A fully qualified path to the image | ||||
|     """ | ||||
|  | ||||
|     # If in debug mode, return URL to the image, not a local file | ||||
|     debug_mode = InvenTreeSetting.get_setting('REPORT_DEBUG_MODE') | ||||
|  | ||||
|     # Check if the file exists | ||||
|     if not filename: | ||||
|         exists = False | ||||
|     else: | ||||
|         try: | ||||
|             full_path = os.path.join(settings.MEDIA_ROOT, filename) | ||||
|             full_path = os.path.abspath(full_path) | ||||
|             exists = os.path.exists(full_path) and os.path.isfile(full_path) | ||||
|         except Exception: | ||||
|             exists = False | ||||
|  | ||||
|     if not exists and not replace_missing: | ||||
|         raise FileNotFoundError(f"Image file '{filename}' not found") | ||||
|  | ||||
|     if debug_mode: | ||||
|         # In debug mode, return a web path | ||||
|         if exists: | ||||
|             return os.path.join(settings.MEDIA_URL, filename) | ||||
|         else: | ||||
|             return os.path.join(settings.STATIC_URL, 'img', replacement_file) | ||||
|     else: | ||||
|         # Return file path | ||||
|         if exists: | ||||
|             path = os.path.join(settings.MEDIA_ROOT, filename) | ||||
|             path = os.path.abspath(path) | ||||
|         else: | ||||
|             path = os.path.join(settings.STATIC_ROOT, 'img', replacement_file) | ||||
|             path = os.path.abspath(path) | ||||
|  | ||||
|         return f"file://{path}" | ||||
| @@ -33,66 +88,55 @@ def asset(filename): | ||||
|  | ||||
| @register.simple_tag() | ||||
| def part_image(part): | ||||
|     """Return a fully-qualified path for a part image.""" | ||||
|     # If in debug mode, return URL to the image, not a local file | ||||
|     debug_mode = InvenTreeSetting.get_setting('REPORT_DEBUG_MODE') | ||||
|     """Return a fully-qualified path for a part image. | ||||
|  | ||||
|     Arguments: | ||||
|         part: a Part model instance | ||||
|  | ||||
|     Raises: | ||||
|         TypeError if provided part is not a Part instance | ||||
|     """ | ||||
|  | ||||
|     if type(part) is Part: | ||||
|         img = part.image.name | ||||
|  | ||||
|     elif type(part) is StockItem: | ||||
|         img = part.part.image.name | ||||
|  | ||||
|     else: | ||||
|         img = '' | ||||
|         raise TypeError("part_image tag requires a Part instance") | ||||
|  | ||||
|     if debug_mode: | ||||
|         if img: | ||||
|             return os.path.join(settings.MEDIA_URL, img) | ||||
|         else: | ||||
|             return os.path.join(settings.STATIC_URL, 'img', 'blank_image.png') | ||||
|  | ||||
|     else: | ||||
|         path = os.path.join(settings.MEDIA_ROOT, img) | ||||
|         path = os.path.abspath(path) | ||||
|  | ||||
|         if not os.path.exists(path) or not os.path.isfile(path): | ||||
|             # Image does not exist | ||||
|             # Return the 'blank' image | ||||
|             path = os.path.join(settings.STATIC_ROOT, 'img', 'blank_image.png') | ||||
|             path = os.path.abspath(path) | ||||
|  | ||||
|         return f"file://{path}" | ||||
|     return uploaded_image(img) | ||||
|  | ||||
|  | ||||
| @register.simple_tag() | ||||
| def company_image(company): | ||||
|     """Return a fully-qualified path for a company image.""" | ||||
|     # If in debug mode, return the URL to the image, not a local file | ||||
|     debug_mode = InvenTreeSetting.get_setting('REPORT_DEBUG_MODE') | ||||
|     """Return a fully-qualified path for a company image. | ||||
|  | ||||
|     Arguments: | ||||
|         company: a Company model instance | ||||
|  | ||||
|     Raises: | ||||
|         TypeError if provided company is not a Company instance | ||||
|     """ | ||||
|  | ||||
|     if type(company) is Company: | ||||
|         img = company.image.name | ||||
|     else: | ||||
|         img = '' | ||||
|         raise TypeError("company_image tag requires a Company instance") | ||||
|  | ||||
|     if debug_mode: | ||||
|         if img: | ||||
|             return os.path.join(settings.MEDIA_URL, img) | ||||
|         else: | ||||
|             return os.path.join(settings.STATIC_URL, 'img', 'blank_image.png') | ||||
|     return uploaded_image(img) | ||||
|  | ||||
|     else: | ||||
|         path = os.path.join(settings.MEDIA_ROOT, img) | ||||
|         path = os.path.abspath(path) | ||||
|  | ||||
|         if not os.path.exists(path) or not os.path.isfile(path): | ||||
|             # Image does not exist | ||||
|             # Return the 'blank' image | ||||
|             path = os.path.join(settings.STATIC_ROOT, 'img', 'blank_image.png') | ||||
|             path = os.path.abspath(path) | ||||
| @register.simple_tag() | ||||
| def logo_image(): | ||||
|     """Return a fully-qualified path for the logo image. | ||||
|  | ||||
|         return f"file://{path}" | ||||
|     - If a custom logo has been provided, return a path to that logo | ||||
|     - Otherwise, return a path to the default InvenTree logo | ||||
|     """ | ||||
|  | ||||
|     # If in debug mode, return URL to the image, not a local file | ||||
|     debug_mode = InvenTreeSetting.get_setting('REPORT_DEBUG_MODE') | ||||
|  | ||||
|     return InvenTree.helpers.getLogoImage(as_file=not debug_mode) | ||||
|  | ||||
|  | ||||
| @register.simple_tag() | ||||
|   | ||||
| @@ -6,15 +6,142 @@ import shutil | ||||
| from django.conf import settings | ||||
| from django.core.cache import cache | ||||
| from django.http.response import StreamingHttpResponse | ||||
| from django.test import TestCase | ||||
| from django.urls import reverse | ||||
|  | ||||
| import report.models as report_models | ||||
| from build.models import Build | ||||
| from common.models import InvenTreeSetting, InvenTreeUserSetting | ||||
| from InvenTree.api_tester import InvenTreeAPITestCase | ||||
| from report.templatetags import barcode as barcode_tags | ||||
| from report.templatetags import report as report_tags | ||||
| from stock.models import StockItem, StockItemAttachment | ||||
|  | ||||
|  | ||||
| class ReportTagTest(TestCase): | ||||
|     """Unit tests for the report template tags""" | ||||
|  | ||||
|     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_asset(self): | ||||
|         """Tests for asset files""" | ||||
|  | ||||
|         # Test that an error is raised if the file does not exist | ||||
|         for b in [True, False]: | ||||
|             self.debug_mode(b) | ||||
|  | ||||
|             with self.assertRaises(FileNotFoundError): | ||||
|                 report_tags.asset("bad_file.txt") | ||||
|  | ||||
|         # Create an asset file | ||||
|         asset_dir = os.path.join(settings.MEDIA_ROOT, 'report', 'assets') | ||||
|         os.makedirs(asset_dir, exist_ok=True) | ||||
|         asset_path = os.path.join(asset_dir, 'test.txt') | ||||
|  | ||||
|         with open(asset_path, 'w') as f: | ||||
|             f.write("dummy data") | ||||
|  | ||||
|         self.debug_mode(True) | ||||
|         asset = report_tags.asset('test.txt') | ||||
|         self.assertEqual(asset, '/media/report/assets/test.txt') | ||||
|  | ||||
|         self.debug_mode(False) | ||||
|         asset = report_tags.asset('test.txt') | ||||
|         self.assertEqual(asset, f'file://{asset_dir}/test.txt') | ||||
|  | ||||
|     def test_uploaded_image(self): | ||||
|         """Tests for retrieving uploaded images""" | ||||
|  | ||||
|         # Test for a missing image | ||||
|         for b in [True, False]: | ||||
|             self.debug_mode(b) | ||||
|  | ||||
|             with self.assertRaises(FileNotFoundError): | ||||
|                 report_tags.uploaded_image('/part/something/test.png', replace_missing=False) | ||||
|  | ||||
|             img = report_tags.uploaded_image('/part/something/other.png') | ||||
|             self.assertTrue('blank_image.png' in img) | ||||
|  | ||||
|         # Create a dummy image | ||||
|         img_path = 'part/images/' | ||||
|         img_path = os.path.join(settings.MEDIA_ROOT, img_path) | ||||
|         img_file = os.path.join(img_path, 'test.jpg') | ||||
|  | ||||
|         os.makedirs(img_path, exist_ok=True) | ||||
|  | ||||
|         with open(img_file, 'w') as f: | ||||
|             f.write("dummy data") | ||||
|  | ||||
|         # Test in debug mode | ||||
|         self.debug_mode(True) | ||||
|         img = report_tags.uploaded_image('part/images/test.jpg') | ||||
|         self.assertEqual(img, '/media/part/images/test.jpg') | ||||
|  | ||||
|         self.debug_mode(False) | ||||
|         img = report_tags.uploaded_image('part/images/test.jpg') | ||||
|         self.assertEqual(img, f'file://{img_path}test.jpg') | ||||
|  | ||||
|     def test_part_image(self): | ||||
|         """Unit tests for the 'part_image' tag""" | ||||
|  | ||||
|         with self.assertRaises(TypeError): | ||||
|             report_tags.part_image(None) | ||||
|  | ||||
|     def test_company_image(self): | ||||
|         """Unit tests for the 'company_image' tag""" | ||||
|  | ||||
|         with self.assertRaises(TypeError): | ||||
|             report_tags.company_image(None) | ||||
|  | ||||
|     def test_logo_image(self): | ||||
|         """Unit tests for the 'logo_image' tag""" | ||||
|  | ||||
|         # By default, should return the core InvenTree logo | ||||
|         for b in [True, False]: | ||||
|             self.debug_mode(b) | ||||
|             logo = report_tags.logo_image() | ||||
|             self.assertIn('inventree.png', logo) | ||||
|  | ||||
|  | ||||
| class BarcodeTagTest(TestCase): | ||||
|     """Unit tests for the barcode template tags""" | ||||
|  | ||||
|     def test_barcode(self): | ||||
|         """Test the barcode generation tag""" | ||||
|  | ||||
|         barcode = barcode_tags.barcode("12345") | ||||
|  | ||||
|         self.assertTrue(type(barcode) == str) | ||||
|         self.assertTrue(barcode.startswith('data:image/png;')) | ||||
|  | ||||
|         # Try with a different format | ||||
|         barcode = barcode_tags.barcode('99999', format='BMP') | ||||
|         self.assertTrue(type(barcode) == str) | ||||
|         self.assertTrue(barcode.startswith('data:image/bmp;')) | ||||
|  | ||||
|     def test_qrcode(self): | ||||
|         """Test the qrcode generation tag""" | ||||
|  | ||||
|         # Test with default settings | ||||
|         qrcode = barcode_tags.qrcode("hello world") | ||||
|         self.assertTrue(type(qrcode) == str) | ||||
|         self.assertTrue(qrcode.startswith('data:image/png;')) | ||||
|         self.assertEqual(len(qrcode), 700) | ||||
|  | ||||
|         # Generate a much larger qrcode | ||||
|         qrcode = barcode_tags.qrcode( | ||||
|             "hello_world", | ||||
|             version=2, | ||||
|             box_size=50, | ||||
|             format='BMP', | ||||
|         ) | ||||
|         self.assertTrue(type(qrcode) == str) | ||||
|         self.assertTrue(qrcode.startswith('data:image/bmp;')) | ||||
|         self.assertEqual(len(qrcode), 309720) | ||||
|  | ||||
|  | ||||
| class ReportTest(InvenTreeAPITestCase): | ||||
|     """Base class for unit testing reporting models""" | ||||
|     fixtures = [ | ||||
|   | ||||
		Reference in New Issue
	
	Block a user