mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
Merge pull request #703 from SchrodingersGat/fixes
Check for missing part thumbnails
This commit is contained in:
commit
5447bc4356
@ -14,6 +14,41 @@ from django.core.exceptions import ValidationError
|
|||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
|
|
||||||
from .version import inventreeVersion, inventreeInstanceName
|
from .version import inventreeVersion, inventreeInstanceName
|
||||||
|
from .settings import MEDIA_URL, STATIC_URL
|
||||||
|
|
||||||
|
|
||||||
|
def getMediaUrl(filename):
|
||||||
|
"""
|
||||||
|
Return the qualified access path for the given file,
|
||||||
|
under the media directory.
|
||||||
|
"""
|
||||||
|
|
||||||
|
return os.path.join(MEDIA_URL, str(filename))
|
||||||
|
|
||||||
|
|
||||||
|
def getStaticUrl(filename):
|
||||||
|
"""
|
||||||
|
Return the qualified access path for the given file,
|
||||||
|
under the static media directory.
|
||||||
|
"""
|
||||||
|
|
||||||
|
return os.path.join(STATIC_URL, str(filename))
|
||||||
|
|
||||||
|
|
||||||
|
def getBlankImage():
|
||||||
|
"""
|
||||||
|
Return the qualified path for the 'blank image' placeholder.
|
||||||
|
"""
|
||||||
|
|
||||||
|
return getStaticUrl("img/blank_image.png")
|
||||||
|
|
||||||
|
|
||||||
|
def getBlankThumbnail():
|
||||||
|
"""
|
||||||
|
Return the qualified path for the 'blank image' thumbnail placeholder.
|
||||||
|
"""
|
||||||
|
|
||||||
|
return getStaticUrl("img/blank_image.thumbnail.png")
|
||||||
|
|
||||||
|
|
||||||
def TestIfImage(img):
|
def TestIfImage(img):
|
||||||
@ -66,7 +101,7 @@ def isNull(text):
|
|||||||
True if the text looks like a null value
|
True if the text looks like a null value
|
||||||
"""
|
"""
|
||||||
|
|
||||||
return str(text).strip().lower() in ['top', 'null', 'none', 'empty', 'false', '-1']
|
return str(text).strip().lower() in ['top', 'null', 'none', 'empty', 'false', '-1', '']
|
||||||
|
|
||||||
|
|
||||||
def decimal2string(d):
|
def decimal2string(d):
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
import django.core.exceptions as django_exceptions
|
import django.core.exceptions as django_exceptions
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
@ -7,6 +8,8 @@ from . import helpers
|
|||||||
|
|
||||||
from mptt.exceptions import InvalidMove
|
from mptt.exceptions import InvalidMove
|
||||||
|
|
||||||
|
from decimal import Decimal
|
||||||
|
|
||||||
from stock.models import StockLocation
|
from stock.models import StockLocation
|
||||||
|
|
||||||
|
|
||||||
@ -72,6 +75,29 @@ class TestHelpers(TestCase):
|
|||||||
self.assertFalse(helpers.str2bool(s))
|
self.assertFalse(helpers.str2bool(s))
|
||||||
self.assertFalse(helpers.str2bool(s, test=False))
|
self.assertFalse(helpers.str2bool(s, test=False))
|
||||||
|
|
||||||
|
def test_isnull(self):
|
||||||
|
|
||||||
|
for s in ['null', 'none', '', '-1', 'false']:
|
||||||
|
self.assertTrue(helpers.isNull(s))
|
||||||
|
|
||||||
|
for s in ['yes', 'frog', 'llama', 'true']:
|
||||||
|
self.assertFalse(helpers.isNull(s))
|
||||||
|
|
||||||
|
def testStaticUrl(self):
|
||||||
|
|
||||||
|
self.assertEqual(helpers.getStaticUrl('test.jpg'), '/static/test.jpg')
|
||||||
|
self.assertEqual(helpers.getBlankImage(), '/static/img/blank_image.png')
|
||||||
|
self.assertEqual(helpers.getBlankThumbnail(), '/static/img/blank_image.thumbnail.png')
|
||||||
|
|
||||||
|
def testMediaUrl(self):
|
||||||
|
|
||||||
|
self.assertEqual(helpers.getMediaUrl('xx/yy.png'), '/media/xx/yy.png')
|
||||||
|
|
||||||
|
def testDecimal2String(self):
|
||||||
|
|
||||||
|
self.assertEqual(helpers.decimal2string(Decimal('1.2345000')), '1.2345')
|
||||||
|
self.assertEqual(helpers.decimal2string('test'), 'test')
|
||||||
|
|
||||||
|
|
||||||
class TestQuoteWrap(TestCase):
|
class TestQuoteWrap(TestCase):
|
||||||
""" Tests for string wrapping """
|
""" Tests for string wrapping """
|
||||||
|
@ -1,7 +1,36 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
from django.apps import AppConfig
|
from django.apps import AppConfig
|
||||||
|
from django.db.utils import OperationalError, ProgrammingError
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
|
|
||||||
class CompanyConfig(AppConfig):
|
class CompanyConfig(AppConfig):
|
||||||
name = 'company'
|
name = 'company'
|
||||||
|
|
||||||
|
def ready(self):
|
||||||
|
"""
|
||||||
|
This function is called whenever the Company app is loaded.
|
||||||
|
"""
|
||||||
|
|
||||||
|
self.generate_company_thumbs()
|
||||||
|
|
||||||
|
def generate_company_thumbs(self):
|
||||||
|
|
||||||
|
from .models import Company
|
||||||
|
|
||||||
|
print("InvenTree: Checking Company image thumbnails")
|
||||||
|
|
||||||
|
try:
|
||||||
|
for company in Company.objects.all():
|
||||||
|
if company.image:
|
||||||
|
url = company.image.thumbnail.name
|
||||||
|
loc = os.path.join(settings.MEDIA_ROOT, url)
|
||||||
|
|
||||||
|
if not os.path.exists(loc):
|
||||||
|
print("InvenTree: Generating thumbnail for Company '{c}'".format(c=company.name))
|
||||||
|
company.image.render_variations(replace=False)
|
||||||
|
except (OperationalError, ProgrammingError):
|
||||||
|
print("Could not generate Company thumbnails")
|
||||||
|
20
InvenTree/company/migrations/0014_auto_20200407_0116.py
Normal file
20
InvenTree/company/migrations/0014_auto_20200407_0116.py
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
# Generated by Django 2.2.10 on 2020-04-07 01:16
|
||||||
|
|
||||||
|
import company.models
|
||||||
|
from django.db import migrations
|
||||||
|
import stdimage.models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('company', '0013_auto_20200406_0131'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='company',
|
||||||
|
name='image',
|
||||||
|
field=stdimage.models.StdImageField(blank=True, null=True, upload_to=company.models.rename_company_image),
|
||||||
|
),
|
||||||
|
]
|
@ -17,10 +17,12 @@ from django.db.models import Sum
|
|||||||
|
|
||||||
from django.apps import apps
|
from django.apps import apps
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.conf import settings
|
|
||||||
|
|
||||||
from markdownx.models import MarkdownxField
|
from markdownx.models import MarkdownxField
|
||||||
|
|
||||||
|
from stdimage.models import StdImageField
|
||||||
|
|
||||||
|
from InvenTree.helpers import getMediaUrl, getBlankImage, getBlankThumbnail
|
||||||
from InvenTree.fields import InvenTreeURLField, RoundingDecimalField
|
from InvenTree.fields import InvenTreeURLField, RoundingDecimalField
|
||||||
from InvenTree.status_codes import OrderStatus
|
from InvenTree.status_codes import OrderStatus
|
||||||
from common.models import Currency
|
from common.models import Currency
|
||||||
@ -90,7 +92,13 @@ class Company(models.Model):
|
|||||||
|
|
||||||
link = InvenTreeURLField(blank=True, help_text=_('Link to external company information'))
|
link = InvenTreeURLField(blank=True, help_text=_('Link to external company information'))
|
||||||
|
|
||||||
image = models.ImageField(upload_to=rename_company_image, max_length=255, null=True, blank=True)
|
image = StdImageField(
|
||||||
|
upload_to=rename_company_image,
|
||||||
|
null=True,
|
||||||
|
blank=True,
|
||||||
|
variations={'thumbnail': (128, 128)},
|
||||||
|
delete_orphans=True,
|
||||||
|
)
|
||||||
|
|
||||||
notes = MarkdownxField(blank=True)
|
notes = MarkdownxField(blank=True)
|
||||||
|
|
||||||
@ -110,10 +118,18 @@ class Company(models.Model):
|
|||||||
""" Return the URL of the image for this company """
|
""" Return the URL of the image for this company """
|
||||||
|
|
||||||
if self.image:
|
if self.image:
|
||||||
return os.path.join(settings.MEDIA_URL, str(self.image.url))
|
return getMediaUrl(self.image.url)
|
||||||
else:
|
else:
|
||||||
return os.path.join(settings.STATIC_URL, 'img/blank_image.png')
|
return 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)
|
||||||
|
else:
|
||||||
|
return getBlankThumbnail()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def part_count(self):
|
def part_count(self):
|
||||||
""" The number of parts supplied by this company """
|
""" The number of parts supplied by this company """
|
||||||
|
@ -32,7 +32,7 @@ class CompanySerializer(InvenTreeModelSerializer):
|
|||||||
url = serializers.CharField(source='get_absolute_url', read_only=True)
|
url = serializers.CharField(source='get_absolute_url', read_only=True)
|
||||||
part_count = serializers.CharField(read_only=True)
|
part_count = serializers.CharField(read_only=True)
|
||||||
|
|
||||||
image = serializers.CharField(source='get_image_url', read_only=True)
|
image = serializers.CharField(source='get_thumbnail_url', read_only=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Company
|
model = Company
|
||||||
@ -64,7 +64,7 @@ class SupplierPartSerializer(InvenTreeModelSerializer):
|
|||||||
part_detail = PartBriefSerializer(source='part', many=False, read_only=True)
|
part_detail = PartBriefSerializer(source='part', many=False, read_only=True)
|
||||||
|
|
||||||
supplier_name = serializers.CharField(source='supplier.name', read_only=True)
|
supplier_name = serializers.CharField(source='supplier.name', read_only=True)
|
||||||
supplier_logo = serializers.CharField(source='supplier.get_image_url', read_only=True)
|
supplier_logo = serializers.CharField(source='supplier.get_thumbnail_url', read_only=True)
|
||||||
|
|
||||||
pricing = serializers.CharField(source='unit_pricing', read_only=True)
|
pricing = serializers.CharField(source='unit_pricing', read_only=True)
|
||||||
|
|
||||||
|
@ -46,7 +46,7 @@ InvenTree | {% trans "Company" %} - {{ company.name }}
|
|||||||
<col width='25'>
|
<col width='25'>
|
||||||
{% if company.website %}
|
{% if company.website %}
|
||||||
<tr>
|
<tr>
|
||||||
<td><span class='fas fa-link'></span></td>
|
<td><span class='fas fa-globe'></span></td>
|
||||||
<td>{% trans "Website" %}</td>
|
<td>{% trans "Website" %}</td>
|
||||||
<td><a href="{{ company.website }}">{{ company.website }}</a></td>
|
<td><a href="{{ company.website }}">{{ company.website }}</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -1,7 +1,35 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
from django.db.utils import OperationalError, ProgrammingError
|
||||||
from django.apps import AppConfig
|
from django.apps import AppConfig
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
|
|
||||||
class PartConfig(AppConfig):
|
class PartConfig(AppConfig):
|
||||||
name = 'part'
|
name = 'part'
|
||||||
|
|
||||||
|
def ready(self):
|
||||||
|
"""
|
||||||
|
This function is called whenever the Part app is loaded.
|
||||||
|
"""
|
||||||
|
|
||||||
|
self.generate_part_thumbnails()
|
||||||
|
|
||||||
|
def generate_part_thumbnails(self):
|
||||||
|
from .models import Part
|
||||||
|
|
||||||
|
print("InvenTree: Checking Part image thumbnails")
|
||||||
|
|
||||||
|
try:
|
||||||
|
for part in Part.objects.all():
|
||||||
|
if part.image:
|
||||||
|
url = part.image.thumbnail.name
|
||||||
|
loc = os.path.join(settings.MEDIA_ROOT, url)
|
||||||
|
|
||||||
|
if not os.path.exists(loc):
|
||||||
|
print("InvenTree: Generating thumbnail for Part '{p}'".format(p=part.name))
|
||||||
|
part.image.render_variations(replace=False)
|
||||||
|
except (OperationalError, ProgrammingError):
|
||||||
|
print("Could not generate Part thumbnails")
|
||||||
|
@ -10,7 +10,6 @@ import os
|
|||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.conf import settings
|
|
||||||
|
|
||||||
from django.db import models, transaction
|
from django.db import models, transaction
|
||||||
from django.db.models import Sum
|
from django.db.models import Sum
|
||||||
@ -300,9 +299,9 @@ class Part(models.Model):
|
|||||||
""" Return the URL of the image for this part """
|
""" Return the URL of the image for this part """
|
||||||
|
|
||||||
if self.image:
|
if self.image:
|
||||||
return os.path.join(settings.MEDIA_URL, str(self.image.url))
|
return helpers.getMediaUrl(self.image.url)
|
||||||
else:
|
else:
|
||||||
return os.path.join(settings.STATIC_URL, 'img/blank_image.png')
|
return helpers.getBlankImage()
|
||||||
|
|
||||||
def get_thumbnail_url(self):
|
def get_thumbnail_url(self):
|
||||||
"""
|
"""
|
||||||
@ -310,9 +309,9 @@ class Part(models.Model):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
if self.image:
|
if self.image:
|
||||||
return os.path.join(settings.MEDIA_URL, str(self.image.thumbnail.url))
|
return helpers.getMediaUrl(self.image.thumbnail.url)
|
||||||
else:
|
else:
|
||||||
return os.path.join(settings.STATIC_URL, 'img/blank_image.thumbnail.png')
|
return helpers.getBlankThumbnail()
|
||||||
|
|
||||||
def validate_unique(self, exclude=None):
|
def validate_unique(self, exclude=None):
|
||||||
""" Validate that a part is 'unique'.
|
""" Validate that a part is 'unique'.
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
{% if item.serialized %}
|
{% if item.serialized %}
|
||||||
<p><i>{{ item.part.full_name}} # {{ item.serial }}</i></p>
|
<p><i>{{ item.part.full_name}} # {{ item.serial }}</i></p>
|
||||||
{% else %}
|
{% else %}
|
||||||
<p><i>{{ item.quantity }} × {{ item.part.full_name }}</i></p>
|
<p><i>{% decimal item.quantity %} × {{ item.part.full_name }}</i></p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<p>
|
<p>
|
||||||
<div class='btn-group'>
|
<div class='btn-group'>
|
||||||
|
Loading…
Reference in New Issue
Block a user