mirror of
https://github.com/inventree/InvenTree.git
synced 2025-04-28 11:36:44 +00:00
Format number (#8482)
* Add extra options for 'format_number' helper * Update documentation * Improved typing hints and docs cleanup * Fix link
This commit is contained in:
parent
ae88124294
commit
da112211e5
@ -7,7 +7,7 @@ title: Machines
|
|||||||
InvenTree has a builtin machine registry. There are different machine types available where each type can have different drivers. Drivers and even custom machine types can be provided by plugins.
|
InvenTree has a builtin machine registry. There are different machine types available where each type can have different drivers. Drivers and even custom machine types can be provided by plugins.
|
||||||
|
|
||||||
!!! info "Requires Redis"
|
!!! info "Requires Redis"
|
||||||
If the machines features is used in production setup using workers, a shared [redis cache](../../start/docker.md#redis-cache) is required to function properly.
|
If the machines features is used in production setup using workers, a shared [redis cache](../../start/processes.md#cache-server) is required to function properly.
|
||||||
|
|
||||||
### Registry
|
### Registry
|
||||||
|
|
||||||
|
@ -41,6 +41,13 @@ A number of helper functions are available for accessing data contained in a par
|
|||||||
|
|
||||||
To return the element at a given index in a container which supports indexed access (such as a [list](https://www.w3schools.com/python/python_lists.asp)), use the `getindex` function:
|
To return the element at a given index in a container which supports indexed access (such as a [list](https://www.w3schools.com/python/python_lists.asp)), use the `getindex` function:
|
||||||
|
|
||||||
|
::: report.templatetags.report.getindex
|
||||||
|
options:
|
||||||
|
show_docstring_description: false
|
||||||
|
show_source: False
|
||||||
|
|
||||||
|
#### Example
|
||||||
|
|
||||||
```html
|
```html
|
||||||
{% raw %}
|
{% raw %}
|
||||||
{% getindex my_list 1 as value %}
|
{% getindex my_list 1 as value %}
|
||||||
@ -53,6 +60,13 @@ Item: {{ value }}
|
|||||||
To return an element corresponding to a certain key in a container which supports key access (such as a [dictionary](https://www.w3schools.com/python/python_dictionaries.asp)), use the `getkey` function:
|
To return an element corresponding to a certain key in a container which supports key access (such as a [dictionary](https://www.w3schools.com/python/python_dictionaries.asp)), use the `getkey` function:
|
||||||
|
|
||||||
|
|
||||||
|
::: report.templatetags.report.getkey
|
||||||
|
options:
|
||||||
|
show_docstring_description: false
|
||||||
|
show_source: False
|
||||||
|
|
||||||
|
#### Example
|
||||||
|
|
||||||
```html
|
```html
|
||||||
{% raw %}
|
{% raw %}
|
||||||
<ul>
|
<ul>
|
||||||
@ -66,8 +80,17 @@ To return an element corresponding to a certain key in a container which support
|
|||||||
|
|
||||||
## Number Formatting
|
## Number Formatting
|
||||||
|
|
||||||
|
### format_number
|
||||||
|
|
||||||
The helper function `format_number` allows for some common number formatting options. It takes a number (or a number-like string) as an input, as well as some formatting arguments. It returns a *string* containing the formatted number:
|
The helper function `format_number` allows for some common number formatting options. It takes a number (or a number-like string) as an input, as well as some formatting arguments. It returns a *string* containing the formatted number:
|
||||||
|
|
||||||
|
::: report.templatetags.report.format_number
|
||||||
|
options:
|
||||||
|
show_docstring_description: false
|
||||||
|
show_source: False
|
||||||
|
|
||||||
|
#### Example
|
||||||
|
|
||||||
```html
|
```html
|
||||||
{% raw %}
|
{% raw %}
|
||||||
{% load report %}
|
{% load report %}
|
||||||
@ -82,15 +105,24 @@ The helper function `format_number` allows for some common number formatting opt
|
|||||||
|
|
||||||
For rendering date and datetime information, the following helper functions are available:
|
For rendering date and datetime information, the following helper functions are available:
|
||||||
|
|
||||||
- `format_date`: Format a date object
|
### format_date
|
||||||
- `format_datetime`: Format a datetime object
|
|
||||||
|
|
||||||
Each of these helper functions takes a date or datetime object as an input, and returns a *string* containing the formatted date or datetime. The following additional arguments are available:
|
::: report.templatetags.report.format_date
|
||||||
|
options:
|
||||||
|
show_docstring_description: false
|
||||||
|
show_source: False
|
||||||
|
|
||||||
|
### format_datetime
|
||||||
|
|
||||||
|
::: report.templatetags.report.format_datetime
|
||||||
|
options:
|
||||||
|
show_docstring_description: false
|
||||||
|
show_source: False
|
||||||
|
|
||||||
|
### Date Formatting
|
||||||
|
|
||||||
|
If not specified, these methods return a result which uses ISO formatting. Refer to the [datetime format codes](https://docs.python.org/3/library/datetime.html#format-codes) for more information! |
|
||||||
|
|
||||||
| Argument | Description |
|
|
||||||
| --- | --- |
|
|
||||||
| timezone | Specify the timezone to render the date in. If not specified, uses the InvenTree server timezone |
|
|
||||||
| format | Specify the format string to use for rendering the date. If not specified, uses ISO formatting. Refer to the [datetime format codes](https://docs.python.org/3/library/datetime.html#format-codes) for more information! |
|
|
||||||
|
|
||||||
### Example
|
### Example
|
||||||
|
|
||||||
@ -106,8 +138,18 @@ Datetime: {% format_datetime my_datetime format="%d-%m-%Y %H:%M%S" %}
|
|||||||
|
|
||||||
## Currency Formatting
|
## Currency Formatting
|
||||||
|
|
||||||
|
### render_currency
|
||||||
|
|
||||||
The helper function `render_currency` allows for simple rendering of currency data. This function can also convert the specified amount of currency into a different target currency:
|
The helper function `render_currency` allows for simple rendering of currency data. This function can also convert the specified amount of currency into a different target currency:
|
||||||
|
|
||||||
|
::: InvenTree.helpers_model.render_currency
|
||||||
|
options:
|
||||||
|
show_docstring_description: false
|
||||||
|
show_source: False
|
||||||
|
|
||||||
|
|
||||||
|
#### Example
|
||||||
|
|
||||||
```html
|
```html
|
||||||
{% raw %}
|
{% raw %}
|
||||||
{% load report %}
|
{% load report %}
|
||||||
@ -124,20 +166,40 @@ Total Price: {% render_currency order.total_price currency='NZD' decimal_places=
|
|||||||
{% endraw %}
|
{% endraw %}
|
||||||
```
|
```
|
||||||
|
|
||||||
The following keyword arguments are available to the `render_currency` function:
|
|
||||||
|
|
||||||
| Argument | Description |
|
|
||||||
| --- | --- |
|
|
||||||
| currency | Specify the currency code to render in (will attempt conversion if different to provided currency) |
|
|
||||||
| decimal_places | Specify the number of decimal places to render |
|
|
||||||
| min_decimal_places | Specify the minimum number of decimal places to render |
|
|
||||||
| max_decimal_places | Specify the maximum number of decimal places to render |
|
|
||||||
| include_symbol | Include currency symbol in rendered value (default = True) |
|
|
||||||
|
|
||||||
## Maths Operations
|
## Maths Operations
|
||||||
|
|
||||||
Simple mathematical operators are available, as demonstrated in the example template below:
|
Simple mathematical operators are available, as demonstrated in the example template below:
|
||||||
|
|
||||||
|
### add
|
||||||
|
|
||||||
|
::: report.templatetags.report.add
|
||||||
|
options:
|
||||||
|
show_docstring_description: false
|
||||||
|
show_source: False
|
||||||
|
|
||||||
|
### subtract
|
||||||
|
|
||||||
|
::: report.templatetags.report.subtract
|
||||||
|
options:
|
||||||
|
show_docstring_description: false
|
||||||
|
show_source: False
|
||||||
|
|
||||||
|
### multiply
|
||||||
|
|
||||||
|
::: report.templatetags.report.multiply
|
||||||
|
options:
|
||||||
|
show_docstring_description: false
|
||||||
|
show_source: False
|
||||||
|
|
||||||
|
### divide
|
||||||
|
|
||||||
|
::: report.templatetags.report.divide
|
||||||
|
options:
|
||||||
|
show_docstring_description: false
|
||||||
|
show_source: False
|
||||||
|
|
||||||
|
### Example
|
||||||
|
|
||||||
```html
|
```html
|
||||||
{% raw %}
|
{% raw %}
|
||||||
<!-- Load the report helper functions -->
|
<!-- Load the report helper functions -->
|
||||||
@ -170,10 +232,15 @@ Total: {% multiply line.purchase_price line.quantity %}<br>
|
|||||||
|
|
||||||
*Media files* are any files uploaded to the InvenTree server by the user. These are stored under the `/media/` directory and can be accessed for use in custom reports or labels.
|
*Media files* are any files uploaded to the InvenTree server by the user. These are stored under the `/media/` directory and can be accessed for use in custom reports or labels.
|
||||||
|
|
||||||
### Uploaded Images
|
### uploaded_image
|
||||||
|
|
||||||
You can access an uploaded image file if you know the *path* of the image, relative to the top-level `/media/` directory. To load the image into a report, use the `{% raw %}{% uploaded_image ... %}{% endraw %}` tag:
|
You can access an uploaded image file if you know the *path* of the image, relative to the top-level `/media/` directory. To load the image into a report, use the `{% raw %}{% uploaded_image ... %}{% endraw %}` tag:
|
||||||
|
|
||||||
|
::: report.templatetags.report.uploaded_image
|
||||||
|
options:
|
||||||
|
show_docstring_description: false
|
||||||
|
show_source: False
|
||||||
|
|
||||||
```html
|
```html
|
||||||
{% raw %}
|
{% raw %}
|
||||||
<!-- Load the report helper functions -->
|
<!-- Load the report helper functions -->
|
||||||
@ -199,7 +266,12 @@ The `{% raw %}{% uploaded_image %}{% endraw %}` tag supports some optional param
|
|||||||
{% endraw %}```
|
{% endraw %}```
|
||||||
|
|
||||||
|
|
||||||
### SVG Images
|
### encode_svg_image
|
||||||
|
|
||||||
|
::: report.templatetags.report.encode_svg_image
|
||||||
|
options:
|
||||||
|
show_docstring_description: false
|
||||||
|
show_source: False
|
||||||
|
|
||||||
SVG images need to be handled in a slightly different manner. When embedding an uploaded SVG image, use the `{% raw %}{% encode_svg_image ... %}{% endraw %}` tag:
|
SVG images need to be handled in a slightly different manner. When embedding an uploaded SVG image, use the `{% raw %}{% encode_svg_image ... %}{% endraw %}` tag:
|
||||||
|
|
||||||
@ -211,10 +283,15 @@ SVG images need to be handled in a slightly different manner. When embedding an
|
|||||||
{% endraw %}
|
{% endraw %}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Part images
|
### part_image
|
||||||
|
|
||||||
A shortcut function is provided for rendering an image associated with a Part instance. You can render the image of the part using the `{% raw %}{% part_image ... %}{% endraw %}` template tag:
|
A shortcut function is provided for rendering an image associated with a Part instance. You can render the image of the part using the `{% raw %}{% part_image ... %}{% endraw %}` template tag:
|
||||||
|
|
||||||
|
::: report.templatetags.report.part_image
|
||||||
|
options:
|
||||||
|
show_docstring_description: false
|
||||||
|
show_source: False
|
||||||
|
|
||||||
```html
|
```html
|
||||||
{% raw %}
|
{% raw %}
|
||||||
<!-- Load the report helper functions -->
|
<!-- Load the report helper functions -->
|
||||||
@ -225,7 +302,7 @@ A shortcut function is provided for rendering an image associated with a Part in
|
|||||||
|
|
||||||
#### Image Arguments
|
#### Image Arguments
|
||||||
|
|
||||||
Any optional arguments which can be used in the [uploaded_image tag](#uploaded-images) can be used here too.
|
Any optional arguments which can be used in the [uploaded_image tag](#uploaded_image) can be used here too.
|
||||||
|
|
||||||
#### Image Variations
|
#### Image Variations
|
||||||
|
|
||||||
@ -243,10 +320,15 @@ The *Part* model supports *preview* (256 x 256) and *thumbnail* (128 x 128) vers
|
|||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
### Company Images
|
### company_image
|
||||||
|
|
||||||
A shortcut function is provided for rendering an image associated with a Company instance. You can render the image of the company using the `{% raw %}{% company_image ... %}{% endraw %}` template tag:
|
A shortcut function is provided for rendering an image associated with a Company instance. You can render the image of the company using the `{% raw %}{% company_image ... %}{% endraw %}` template tag:
|
||||||
|
|
||||||
|
::: report.templatetags.report.company_image
|
||||||
|
options:
|
||||||
|
show_docstring_description: false
|
||||||
|
show_source: False
|
||||||
|
|
||||||
```html
|
```html
|
||||||
{% raw %}
|
{% raw %}
|
||||||
<!-- Load the report helper functions -->
|
<!-- Load the report helper functions -->
|
||||||
@ -326,7 +408,14 @@ You can add asset images to the reports and labels by using the `{% raw %}{% ass
|
|||||||
|
|
||||||
## Part Parameters
|
## Part Parameters
|
||||||
|
|
||||||
If you need to load a part parameter for a particular Part, within the context of your template, you can use the `part_parameter` template tag.
|
If you need to load a part parameter for a particular Part, within the context of your template, you can use the `part_parameter` template tag:
|
||||||
|
|
||||||
|
::: report.templatetags.report.part_parameter
|
||||||
|
options:
|
||||||
|
show_docstring_description: false
|
||||||
|
show_source: False
|
||||||
|
|
||||||
|
### Example
|
||||||
|
|
||||||
The following example assumes that you have a report or label which contains a valid [Part](../part/part.md) instance:
|
The following example assumes that you have a report or label which contains a valid [Part](../part/part.md) instance:
|
||||||
|
|
||||||
|
@ -177,7 +177,7 @@ Asset files can be rendered directly into the template as follows
|
|||||||
If the requested asset name does not match the name of an uploaded asset, the template will continue without loading the image.
|
If the requested asset name does not match the name of an uploaded asset, the template will continue without loading the image.
|
||||||
|
|
||||||
!!! info "Assets location"
|
!!! info "Assets location"
|
||||||
You need to ensure your asset images to the report/assets directory in the [data directory](../start/intro.md#file-storage). Upload new assets via the [admin interface](../settings/admin.md) to ensure they are uploaded to the correct location on the server.
|
Upload new assets via the [admin interface](../settings/admin.md) to ensure they are uploaded to the correct location on the server.
|
||||||
|
|
||||||
|
|
||||||
## Report Snippets
|
## Report Snippets
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
import io
|
import io
|
||||||
import logging
|
import logging
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
|
from typing import Optional
|
||||||
from urllib.parse import urljoin
|
from urllib.parse import urljoin
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
@ -179,12 +180,12 @@ def download_image_from_url(remote_url, timeout=2.5):
|
|||||||
|
|
||||||
|
|
||||||
def render_currency(
|
def render_currency(
|
||||||
money,
|
money: Money,
|
||||||
decimal_places=None,
|
decimal_places: Optional[int] = None,
|
||||||
currency=None,
|
currency: Optional[str] = None,
|
||||||
min_decimal_places=None,
|
min_decimal_places: Optional[int] = None,
|
||||||
max_decimal_places=None,
|
max_decimal_places: Optional[int] = None,
|
||||||
include_symbol=True,
|
include_symbol: bool = True,
|
||||||
):
|
):
|
||||||
"""Render a currency / Money object to a formatted string (e.g. for reports).
|
"""Render a currency / Money object to a formatted string (e.g. for reports).
|
||||||
|
|
||||||
|
@ -3,7 +3,9 @@
|
|||||||
import base64
|
import base64
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
|
from datetime import date, datetime
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
|
from typing import Any, Optional
|
||||||
|
|
||||||
from django import template
|
from django import template
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
@ -28,7 +30,7 @@ logger = logging.getLogger('inventree')
|
|||||||
|
|
||||||
|
|
||||||
@register.simple_tag()
|
@register.simple_tag()
|
||||||
def getindex(container: list, index: int):
|
def getindex(container: list, index: int) -> Any:
|
||||||
"""Return the value contained at the specified index of the list.
|
"""Return the value contained at the specified index of the list.
|
||||||
|
|
||||||
This function is provideed to get around template rendering limitations.
|
This function is provideed to get around template rendering limitations.
|
||||||
@ -55,7 +57,7 @@ def getindex(container: list, index: int):
|
|||||||
|
|
||||||
|
|
||||||
@register.simple_tag()
|
@register.simple_tag()
|
||||||
def getkey(container: dict, key):
|
def getkey(container: dict, key: str) -> Any:
|
||||||
"""Perform key lookup in the provided dict object.
|
"""Perform key lookup in the provided dict object.
|
||||||
|
|
||||||
This function is provided to get around template rendering limitations.
|
This function is provided to get around template rendering limitations.
|
||||||
@ -82,7 +84,7 @@ def asset(filename):
|
|||||||
filename: Asset filename (relative to the 'assets' media directory)
|
filename: Asset filename (relative to the 'assets' media directory)
|
||||||
|
|
||||||
Raises:
|
Raises:
|
||||||
FileNotFoundError if file does not exist
|
FileNotFoundError: If file does not exist
|
||||||
"""
|
"""
|
||||||
if type(filename) is SafeString:
|
if type(filename) is SafeString:
|
||||||
# Prepend an empty string to enforce 'stringiness'
|
# Prepend an empty string to enforce 'stringiness'
|
||||||
@ -104,30 +106,31 @@ def asset(filename):
|
|||||||
|
|
||||||
@register.simple_tag()
|
@register.simple_tag()
|
||||||
def uploaded_image(
|
def uploaded_image(
|
||||||
filename,
|
filename: str,
|
||||||
replace_missing=True,
|
replace_missing: bool = True,
|
||||||
replacement_file='blank_image.png',
|
replacement_file: str = 'blank_image.png',
|
||||||
validate=True,
|
validate: bool = True,
|
||||||
|
width: Optional[int] = None,
|
||||||
|
height: Optional[int] = None,
|
||||||
|
rotate: Optional[float] = None,
|
||||||
**kwargs,
|
**kwargs,
|
||||||
):
|
) -> str:
|
||||||
"""Return raw image data from an 'uploaded' image.
|
"""Return raw image data from an 'uploaded' image.
|
||||||
|
|
||||||
Arguments:
|
Arguments:
|
||||||
filename: The filename of the image relative to the MEDIA_ROOT directory
|
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 (default = True)
|
replace_missing: Optionally return a placeholder image if the provided filename does not exist (default = True)
|
||||||
replacement_file: The filename of the placeholder image (default = 'blank_image.png')
|
replacement_file: The filename of the placeholder image (default = 'blank_image.png')
|
||||||
validate: Optionally validate that the file is a valid image file (default = True)
|
validate: Optionally validate that the file is a valid image file
|
||||||
|
width: Optional width of the image
|
||||||
kwargs:
|
height: Optional height of the image
|
||||||
width: Optional width of the image (default = None)
|
|
||||||
height: Optional height of the image (default = None)
|
|
||||||
rotate: Optional rotation to apply to the image
|
rotate: Optional rotation to apply to the image
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Binary image data to be rendered directly in a <img> tag
|
Binary image data to be rendered directly in a <img> tag
|
||||||
|
|
||||||
Raises:
|
Raises:
|
||||||
FileNotFoundError if the file does not exist
|
FileNotFoundError: If the file does not exist
|
||||||
"""
|
"""
|
||||||
if type(filename) is SafeString:
|
if type(filename) is SafeString:
|
||||||
# Prepend an empty string to enforce 'stringiness'
|
# Prepend an empty string to enforce 'stringiness'
|
||||||
@ -169,9 +172,6 @@ def uploaded_image(
|
|||||||
# A placeholder image showing that the image is missing
|
# A placeholder image showing that the image is missing
|
||||||
img = Image.new('RGB', (64, 64), color='red')
|
img = Image.new('RGB', (64, 64), color='red')
|
||||||
|
|
||||||
width = kwargs.get('width')
|
|
||||||
height = kwargs.get('height')
|
|
||||||
|
|
||||||
if width is not None:
|
if width is not None:
|
||||||
try:
|
try:
|
||||||
width = int(width)
|
width = int(width)
|
||||||
@ -199,7 +199,7 @@ def uploaded_image(
|
|||||||
img = img.resize((wsize, height))
|
img = img.resize((wsize, height))
|
||||||
|
|
||||||
# Optionally rotate the image
|
# Optionally rotate the image
|
||||||
if rotate := kwargs.get('rotate'):
|
if rotate is not None:
|
||||||
try:
|
try:
|
||||||
rotate = int(rotate)
|
rotate = int(rotate)
|
||||||
img = img.rotate(rotate)
|
img = img.rotate(rotate)
|
||||||
@ -213,7 +213,7 @@ def uploaded_image(
|
|||||||
|
|
||||||
|
|
||||||
@register.simple_tag()
|
@register.simple_tag()
|
||||||
def encode_svg_image(filename):
|
def encode_svg_image(filename: str) -> str:
|
||||||
"""Return a base64-encoded svg image data string."""
|
"""Return a base64-encoded svg image data string."""
|
||||||
if type(filename) is SafeString:
|
if type(filename) is SafeString:
|
||||||
# Prepend an empty string to enforce 'stringiness'
|
# Prepend an empty string to enforce 'stringiness'
|
||||||
@ -243,7 +243,7 @@ def encode_svg_image(filename):
|
|||||||
|
|
||||||
|
|
||||||
@register.simple_tag()
|
@register.simple_tag()
|
||||||
def part_image(part: Part, preview=False, thumbnail=False, **kwargs):
|
def part_image(part: Part, preview: bool = False, thumbnail: bool = False, **kwargs):
|
||||||
"""Return a fully-qualified path for a part image.
|
"""Return a fully-qualified path for a part image.
|
||||||
|
|
||||||
Arguments:
|
Arguments:
|
||||||
@ -252,7 +252,7 @@ def part_image(part: Part, preview=False, thumbnail=False, **kwargs):
|
|||||||
thumbnail: Return the thumbnail image (default = False)
|
thumbnail: Return the thumbnail image (default = False)
|
||||||
|
|
||||||
Raises:
|
Raises:
|
||||||
TypeError if provided part is not a Part instance
|
TypeError: If provided part is not a Part instance
|
||||||
"""
|
"""
|
||||||
if type(part) is not Part:
|
if type(part) is not Part:
|
||||||
raise TypeError(_('part_image tag requires a Part instance'))
|
raise TypeError(_('part_image tag requires a Part instance'))
|
||||||
@ -268,7 +268,7 @@ def part_image(part: Part, preview=False, thumbnail=False, **kwargs):
|
|||||||
|
|
||||||
|
|
||||||
@register.simple_tag()
|
@register.simple_tag()
|
||||||
def part_parameter(part: Part, parameter_name: str):
|
def part_parameter(part: Part, parameter_name: str) -> str:
|
||||||
"""Return a PartParameter object for the given part and parameter name.
|
"""Return a PartParameter object for the given part and parameter name.
|
||||||
|
|
||||||
Arguments:
|
Arguments:
|
||||||
@ -284,7 +284,9 @@ def part_parameter(part: Part, parameter_name: str):
|
|||||||
|
|
||||||
|
|
||||||
@register.simple_tag()
|
@register.simple_tag()
|
||||||
def company_image(company, preview=False, thumbnail=False, **kwargs):
|
def company_image(
|
||||||
|
company: Company, preview: bool = False, thumbnail: bool = False, **kwargs
|
||||||
|
) -> str:
|
||||||
"""Return a fully-qualified path for a company image.
|
"""Return a fully-qualified path for a company image.
|
||||||
|
|
||||||
Arguments:
|
Arguments:
|
||||||
@ -293,7 +295,7 @@ def company_image(company, preview=False, thumbnail=False, **kwargs):
|
|||||||
thumbnail: Return the thumbnail image (default = False)
|
thumbnail: Return the thumbnail image (default = False)
|
||||||
|
|
||||||
Raises:
|
Raises:
|
||||||
TypeError if provided company is not a Company instance
|
TypeError: If provided company is not a Company instance
|
||||||
"""
|
"""
|
||||||
if type(company) is not Company:
|
if type(company) is not Company:
|
||||||
raise TypeError(_('company_image tag requires a Company instance'))
|
raise TypeError(_('company_image tag requires a Company instance'))
|
||||||
@ -309,7 +311,7 @@ def company_image(company, preview=False, thumbnail=False, **kwargs):
|
|||||||
|
|
||||||
|
|
||||||
@register.simple_tag()
|
@register.simple_tag()
|
||||||
def logo_image(**kwargs):
|
def logo_image(**kwargs) -> str:
|
||||||
"""Return a fully-qualified path for the logo image.
|
"""Return a fully-qualified path for the logo image.
|
||||||
|
|
||||||
- If a custom logo has been provided, return a path to that logo
|
- If a custom logo has been provided, return a path to that logo
|
||||||
@ -322,7 +324,7 @@ def logo_image(**kwargs):
|
|||||||
|
|
||||||
|
|
||||||
@register.simple_tag()
|
@register.simple_tag()
|
||||||
def internal_link(link, text):
|
def internal_link(link, text) -> str:
|
||||||
"""Make a <a></a> href which points to an InvenTree URL.
|
"""Make a <a></a> href which points to an InvenTree URL.
|
||||||
|
|
||||||
Uses the InvenTree.helpers_model.construct_absolute_url function to build the URL.
|
Uses the InvenTree.helpers_model.construct_absolute_url function to build the URL.
|
||||||
@ -396,13 +398,20 @@ def render_html_text(text: str, **kwargs):
|
|||||||
|
|
||||||
|
|
||||||
@register.simple_tag
|
@register.simple_tag
|
||||||
def format_number(number, **kwargs):
|
def format_number(
|
||||||
|
number,
|
||||||
|
decimal_places: Optional[int] = None,
|
||||||
|
integer: bool = False,
|
||||||
|
leading: int = 0,
|
||||||
|
separator: Optional[str] = None,
|
||||||
|
) -> str:
|
||||||
"""Render a number with optional formatting options.
|
"""Render a number with optional formatting options.
|
||||||
|
|
||||||
kwargs:
|
Arguments:
|
||||||
decimal_places: Number of decimal places to render
|
decimal_places: Number of decimal places to render
|
||||||
integer: Boolean, whether to render the number as an integer
|
integer: Boolean, whether to render the number as an integer
|
||||||
leading: Number of leading zeros
|
leading: Number of leading zeros (default = 0)
|
||||||
|
separator: Character to use as a thousands separator (default = None)
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
number = Decimal(str(number))
|
number = Decimal(str(number))
|
||||||
@ -410,28 +419,30 @@ def format_number(number, **kwargs):
|
|||||||
# If the number cannot be converted to a Decimal, just return the original value
|
# If the number cannot be converted to a Decimal, just return the original value
|
||||||
return str(number)
|
return str(number)
|
||||||
|
|
||||||
if kwargs.get('integer', False):
|
if integer:
|
||||||
# Convert to integer
|
# Convert to integer
|
||||||
number = Decimal(int(number))
|
number = Decimal(int(number))
|
||||||
|
|
||||||
# Normalize the number (remove trailing zeroes)
|
# Normalize the number (remove trailing zeroes)
|
||||||
number = number.normalize()
|
number = number.normalize()
|
||||||
|
|
||||||
decimals = kwargs.get('decimal_places')
|
decimal_places
|
||||||
|
|
||||||
if decimals is not None:
|
if decimal_places is not None:
|
||||||
try:
|
try:
|
||||||
decimals = int(decimals)
|
decimal_places = int(decimal_places)
|
||||||
number = round(number, decimals)
|
number = round(number, decimal_places)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# Re-encode, and normalize again
|
# Re-encode, and normalize again
|
||||||
value = Decimal(number).normalize()
|
value = Decimal(number).normalize()
|
||||||
value = format(value, 'f')
|
|
||||||
value = str(value)
|
|
||||||
|
|
||||||
leading = kwargs.get('leading')
|
if separator:
|
||||||
|
value = f'{value:,}'
|
||||||
|
value = value.replace(',', separator)
|
||||||
|
else:
|
||||||
|
value = f'{value}'
|
||||||
|
|
||||||
if leading is not None:
|
if leading is not None:
|
||||||
try:
|
try:
|
||||||
@ -444,37 +455,39 @@ def format_number(number, **kwargs):
|
|||||||
|
|
||||||
|
|
||||||
@register.simple_tag
|
@register.simple_tag
|
||||||
def format_datetime(datetime, timezone=None, fmt=None):
|
def format_datetime(
|
||||||
|
dt: datetime, timezone: Optional[str] = None, fmt: Optional[str] = None
|
||||||
|
):
|
||||||
"""Format a datetime object for display.
|
"""Format a datetime object for display.
|
||||||
|
|
||||||
Arguments:
|
Arguments:
|
||||||
datetime: The datetime object to format
|
dt: The datetime object to format
|
||||||
timezone: The timezone to use for the date (defaults to the server timezone)
|
timezone: The timezone to use for the date (defaults to the server timezone)
|
||||||
fmt: The format string to use (defaults to ISO formatting)
|
fmt: The format string to use (defaults to ISO formatting)
|
||||||
"""
|
"""
|
||||||
datetime = InvenTree.helpers.to_local_time(datetime, timezone)
|
dt = InvenTree.helpers.to_local_time(dt, timezone)
|
||||||
|
|
||||||
if fmt:
|
if fmt:
|
||||||
return datetime.strftime(fmt)
|
return dt.strftime(fmt)
|
||||||
else:
|
else:
|
||||||
return datetime.isoformat()
|
return dt.isoformat()
|
||||||
|
|
||||||
|
|
||||||
@register.simple_tag
|
@register.simple_tag
|
||||||
def format_date(date, timezone=None, fmt=None):
|
def format_date(dt: date, timezone: Optional[str] = None, fmt: Optional[str] = None):
|
||||||
"""Format a date object for display.
|
"""Format a date object for display.
|
||||||
|
|
||||||
Arguments:
|
Arguments:
|
||||||
date: The date to format
|
dt: The date to format
|
||||||
timezone: The timezone to use for the date (defaults to the server timezone)
|
timezone: The timezone to use for the date (defaults to the server timezone)
|
||||||
fmt: The format string to use (defaults to ISO formatting)
|
fmt: The format string to use (defaults to ISO formatting)
|
||||||
"""
|
"""
|
||||||
date = InvenTree.helpers.to_local_time(date, timezone).date()
|
dt = InvenTree.helpers.to_local_time(dt, timezone).date()
|
||||||
|
|
||||||
if fmt:
|
if fmt:
|
||||||
return date.strftime(fmt)
|
return dt.strftime(fmt)
|
||||||
else:
|
else:
|
||||||
return date.isoformat()
|
return dt.isoformat()
|
||||||
|
|
||||||
|
|
||||||
@register.simple_tag()
|
@register.simple_tag()
|
||||||
|
@ -156,6 +156,18 @@ class ReportTagTest(TestCase):
|
|||||||
self.assertEqual(report_tags.multiply(2.3, 4), 9.2)
|
self.assertEqual(report_tags.multiply(2.3, 4), 9.2)
|
||||||
self.assertEqual(report_tags.divide(100, 5), 20)
|
self.assertEqual(report_tags.divide(100, 5), 20)
|
||||||
|
|
||||||
|
def test_number_tags(self):
|
||||||
|
"""Simple tests for number formatting tags."""
|
||||||
|
fn = report_tags.format_number
|
||||||
|
|
||||||
|
self.assertEqual(fn(1234), '1234')
|
||||||
|
self.assertEqual(fn(1234.5678, decimal_places=2), '1234.57')
|
||||||
|
self.assertEqual(fn(1234.5678, decimal_places=3), '1234.568')
|
||||||
|
self.assertEqual(fn(-9999.5678, decimal_places=2, separator=','), '-9,999.57')
|
||||||
|
self.assertEqual(
|
||||||
|
fn(9988776655.4321, integer=True, separator=' '), '9 988 776 655'
|
||||||
|
)
|
||||||
|
|
||||||
@override_settings(TIME_ZONE='America/New_York')
|
@override_settings(TIME_ZONE='America/New_York')
|
||||||
def test_date_tags(self):
|
def test_date_tags(self):
|
||||||
"""Test for date formatting tags.
|
"""Test for date formatting tags.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user