diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index eb5d86b616..49d858702a 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -9,13 +9,14 @@ jobs:
tweet:
runs-on: ubuntu-latest
steps:
- - uses: ethomson/send-tweet-action@v1
+ - uses: Eomm/why-don-t-you-tweet@v1
with:
- status: "InvenTree release ${{ github.event.release.tag_name }} is out now! Release notes: ${{ github.event.release.html_url }} #opensource #inventree"
- consumer-key: ${{ secrets.TWITTER_CONSUMER_API_KEY }}
- consumer-secret: ${{ secrets.TWITTER_CONSUMER_API_SECRET }}
- access-token: ${{ secrets.TWITTER_ACCESS_TOKEN }}
- access-token-secret: ${{ secrets.TWITTER_ACCESS_TOKEN_SECRET }}
+ tweet-message: "InvenTree release ${{ github.event.release.tag_name }} is out now! Release notes: ${{ github.event.release.html_url }} #opensource #inventree"
+ env:
+ TWITTER_CONSUMER_API_KEY: ${{ secrets.TWITTER_CONSUMER_API_KEY }}
+ TWITTER_CONSUMER_API_SECRET: ${{ secrets.TWITTER_CONSUMER_API_SECRET }}
+ TWITTER_ACCESS_TOKEN: ${{ secrets.TWITTER_ACCESS_TOKEN }}
+ TWITTER_ACCESS_TOKEN_SECRET: ${{ secrets.TWITTER_ACCESS_TOKEN_SECRET }}
reddit:
runs-on: ubuntu-latest
diff --git a/InvenTree/InvenTree/helpers.py b/InvenTree/InvenTree/helpers.py
index fdc6380138..3bdab4c472 100644
--- a/InvenTree/InvenTree/helpers.py
+++ b/InvenTree/InvenTree/helpers.py
@@ -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, custom=True):
+ """Return the InvenTree logo image, or a custom logo if available."""
+
+ """Return the path to the logo-file."""
+ if custom and 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):
diff --git a/InvenTree/InvenTree/settings.py b/InvenTree/InvenTree/settings.py
index 447e07b09c..eb18342bd1 100644
--- a/InvenTree/InvenTree/settings.py
+++ b/InvenTree/InvenTree/settings.py
@@ -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")
diff --git a/InvenTree/InvenTree/tests.py b/InvenTree/InvenTree/tests.py
index 1f9c11e7fc..c0bd93b2c1 100644
--- a/InvenTree/InvenTree/tests.py
+++ b/InvenTree/InvenTree/tests.py
@@ -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."""
diff --git a/InvenTree/company/models.py b/InvenTree/company/models.py
index 1a18d39d14..fa68dfcf1b 100644
--- a/InvenTree/company/models.py
+++ b/InvenTree/company/models.py
@@ -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):
diff --git a/InvenTree/order/models.py b/InvenTree/order/models.py
index 22ea2dba8e..fef6344240 100644
--- a/InvenTree/order/models.py
+++ b/InvenTree/order/models.py
@@ -1217,7 +1217,7 @@ class SalesOrderShipment(models.Model):
reference = models.CharField(
max_length=100,
blank=False,
- verbose_name=('Shipment'),
+ verbose_name=_('Shipment'),
help_text=_('Shipment number'),
default='1',
)
diff --git a/InvenTree/order/serializers.py b/InvenTree/order/serializers.py
index dafd9b5817..e2ec2c8761 100644
--- a/InvenTree/order/serializers.py
+++ b/InvenTree/order/serializers.py
@@ -981,6 +981,10 @@ class SalesOrderShipmentCompleteSerializer(serializers.ModelSerializer):
# Extract shipping date (defaults to today's date)
shipment_date = data.get('shipment_date', datetime.now())
+ if shipment_date is None:
+ # Shipment date should not be None - check above only
+ # checks if shipment_date exists in data
+ shipment_date = datetime.now()
shipment.complete_shipment(
user,
diff --git a/InvenTree/part/templatetags/inventree_extras.py b/InvenTree/part/templatetags/inventree_extras.py
index 4f250959ed..92f760e1d4 100644
--- a/InvenTree/part/templatetags/inventree_extras.py
+++ b/InvenTree/part/templatetags/inventree_extras.py
@@ -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.
diff --git a/InvenTree/report/models.py b/InvenTree/report/models.py
index 5072028394..39ca0f7cd7 100644
--- a/InvenTree/report/models.py
+++ b/InvenTree/report/models.py
@@ -539,10 +539,16 @@ class ReportAsset(models.Model):
"""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")
+ )
diff --git a/InvenTree/report/templates/report/inventree_build_order_base.html b/InvenTree/report/templates/report/inventree_build_order_base.html
index 5e73491d39..20f72e58ee 100644
--- a/InvenTree/report/templates/report/inventree_build_order_base.html
+++ b/InvenTree/report/templates/report/inventree_build_order_base.html
@@ -78,8 +78,7 @@ content: "v{{report_revision}} - {{ date.isoformat }}";
{% endblock %}
{% block header_content %}
-
-
+