mirror of
https://github.com/inventree/InvenTree.git
synced 2026-06-10 02:36:59 +00:00
Merge remote-tracking branch 'inventree/master'
This commit is contained in:
@@ -0,0 +1,31 @@
|
|||||||
|
# Runs on releases
|
||||||
|
|
||||||
|
name: Publish release notes
|
||||||
|
on:
|
||||||
|
release:
|
||||||
|
types: [published]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
tweet:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: ethomson/send-tweet-action@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 }}
|
||||||
|
|
||||||
|
reddit:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: bluwy/release-for-reddit-action@v1
|
||||||
|
with:
|
||||||
|
username: ${{ secrets.REDDIT_USERNAME }}
|
||||||
|
password: ${{ secrets.REDDIT_PASSWORD }}
|
||||||
|
app-id: ${{ secrets.REDDIT_APP_ID }}
|
||||||
|
app-secret: ${{ secrets.REDDIT_APP_SECRET }}
|
||||||
|
subreddit: InvenTree
|
||||||
|
title: "InvenTree version ${{ github.event.release.tag_name }} released"
|
||||||
|
comment: "${{ github.event.release.body }}"
|
||||||
@@ -133,8 +133,12 @@ class InvenTreeAPITestCase(UserMixin, APITestCase):
|
|||||||
if expected_code is not None:
|
if expected_code is not None:
|
||||||
|
|
||||||
if response.status_code != expected_code:
|
if response.status_code != expected_code:
|
||||||
print(f"Unexpected response at '{url}':")
|
print(f"Unexpected response at '{url}': status code = {response.status_code}")
|
||||||
print(response.data)
|
|
||||||
|
if hasattr(response, 'data'):
|
||||||
|
print(response.data)
|
||||||
|
else:
|
||||||
|
print(f"(response object {type(response)} has no 'data' attribute")
|
||||||
|
|
||||||
self.assertEqual(response.status_code, expected_code)
|
self.assertEqual(response.status_code, expected_code)
|
||||||
|
|
||||||
|
|||||||
@@ -2,11 +2,15 @@
|
|||||||
|
|
||||||
|
|
||||||
# InvenTree API version
|
# InvenTree API version
|
||||||
INVENTREE_API_VERSION = 61
|
INVENTREE_API_VERSION = 64
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Increment this API version number whenever there is a significant change to the API that any clients need to know about
|
Increment this API version number whenever there is a significant change to the API that any clients need to know about
|
||||||
|
|
||||||
|
v64 -> 2022-07-08 : https://github.com/inventree/InvenTree/pull/3310
|
||||||
|
- Annotate 'on_order' quantity to BOM list API
|
||||||
|
- Allow BOM List API endpoint to be filtered by "on_order" parameter
|
||||||
|
|
||||||
v63 -> 2022-07-06 : https://github.com/inventree/InvenTree/pull/3301
|
v63 -> 2022-07-06 : https://github.com/inventree/InvenTree/pull/3301
|
||||||
- Allow BOM List API endpoint to be filtered by "available_stock" paramater
|
- Allow BOM List API endpoint to be filtered by "available_stock" paramater
|
||||||
|
|
||||||
|
|||||||
@@ -63,10 +63,15 @@ class InvenTreeModelMoneyField(ModelMoneyField):
|
|||||||
# Set a minimum value validator
|
# Set a minimum value validator
|
||||||
validators = kwargs.get('validators', [])
|
validators = kwargs.get('validators', [])
|
||||||
|
|
||||||
|
allow_negative = kwargs.pop('allow_negative', False)
|
||||||
|
|
||||||
|
# If no validators are provided, add some "standard" ones
|
||||||
if len(validators) == 0:
|
if len(validators) == 0:
|
||||||
validators.append(
|
|
||||||
MinMoneyValidator(0),
|
if not allow_negative:
|
||||||
)
|
validators.append(
|
||||||
|
MinMoneyValidator(0),
|
||||||
|
)
|
||||||
|
|
||||||
kwargs['validators'] = validators
|
kwargs['validators'] = validators
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,156 @@
|
|||||||
|
"""Custom string formatting functions and helpers"""
|
||||||
|
|
||||||
|
import re
|
||||||
|
import string
|
||||||
|
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
|
def parse_format_string(fmt_string: str) -> dict:
|
||||||
|
"""Extract formatting information from the provided format string.
|
||||||
|
|
||||||
|
Returns a dict object which contains structured information about the format groups
|
||||||
|
"""
|
||||||
|
|
||||||
|
groups = string.Formatter().parse(fmt_string)
|
||||||
|
|
||||||
|
info = {}
|
||||||
|
|
||||||
|
for group in groups:
|
||||||
|
# Skip any group which does not have a named value
|
||||||
|
if not group[1]:
|
||||||
|
continue
|
||||||
|
|
||||||
|
info[group[1]] = {
|
||||||
|
'format': group[1],
|
||||||
|
'prefix': group[0],
|
||||||
|
}
|
||||||
|
|
||||||
|
return info
|
||||||
|
|
||||||
|
|
||||||
|
def construct_format_regex(fmt_string: str) -> str:
|
||||||
|
r"""Construct a regular expression based on a provided format string
|
||||||
|
|
||||||
|
This function turns a python format string into a regular expression,
|
||||||
|
which can be used for two purposes:
|
||||||
|
|
||||||
|
- Ensure that a particular string matches the specified format
|
||||||
|
- Extract named variables from a matching string
|
||||||
|
|
||||||
|
This function also provides support for wildcard characters:
|
||||||
|
|
||||||
|
- '?' provides single character matching; is converted to a '.' (period) for regex
|
||||||
|
- '#' provides single digit matching; is converted to '\d'
|
||||||
|
|
||||||
|
Args:
|
||||||
|
fmt_string: A typical format string e.g. "PO-???-{ref:04d}"
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: A regular expression pattern e.g. ^PO\-...\-(?P<ref>.*)$
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
ValueError: Format string is invalid
|
||||||
|
"""
|
||||||
|
|
||||||
|
pattern = "^"
|
||||||
|
|
||||||
|
for group in string.Formatter().parse(fmt_string):
|
||||||
|
prefix = group[0] # Prefix (literal text appearing before this group)
|
||||||
|
name = group[1] # Name of this format variable
|
||||||
|
format = group[2] # Format specifier e.g :04d
|
||||||
|
|
||||||
|
rep = [
|
||||||
|
'+', '-', '.',
|
||||||
|
'{', '}', '(', ')',
|
||||||
|
'^', '$', '~', '!', '@', ':', ';', '|', '\'', '"',
|
||||||
|
]
|
||||||
|
|
||||||
|
# Escape any special regex characters
|
||||||
|
for ch in rep:
|
||||||
|
prefix = prefix.replace(ch, '\\' + ch)
|
||||||
|
|
||||||
|
# Replace ? with single-character match
|
||||||
|
prefix = prefix.replace('?', '.')
|
||||||
|
|
||||||
|
# Replace # with single-digit match
|
||||||
|
prefix = prefix.replace('#', r'\d')
|
||||||
|
|
||||||
|
pattern += prefix
|
||||||
|
|
||||||
|
# Add a named capture group for the format entry
|
||||||
|
if name:
|
||||||
|
|
||||||
|
# Check if integer values are requried
|
||||||
|
if format.endswith('d'):
|
||||||
|
chr = '\d'
|
||||||
|
else:
|
||||||
|
chr = '.'
|
||||||
|
|
||||||
|
# Specify width
|
||||||
|
# TODO: Introspect required width
|
||||||
|
w = '+'
|
||||||
|
|
||||||
|
pattern += f"(?P<{name}>{chr}{w})"
|
||||||
|
|
||||||
|
pattern += "$"
|
||||||
|
|
||||||
|
return pattern
|
||||||
|
|
||||||
|
|
||||||
|
def validate_string(value: str, fmt_string: str) -> str:
|
||||||
|
"""Validate that the provided string matches the specified format.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
value: The string to be tested e.g. 'SO-1234-ABC',
|
||||||
|
fmt_string: The required format e.g. 'SO-{ref}-???',
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: True if the value matches the required format, else False
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
ValueError: The provided format string is invalid
|
||||||
|
"""
|
||||||
|
|
||||||
|
pattern = construct_format_regex(fmt_string)
|
||||||
|
|
||||||
|
result = re.match(pattern, value)
|
||||||
|
|
||||||
|
return result is not None
|
||||||
|
|
||||||
|
|
||||||
|
def extract_named_group(name: str, value: str, fmt_string: str) -> str:
|
||||||
|
"""Extract a named value from the provided string, given the provided format string
|
||||||
|
|
||||||
|
Args:
|
||||||
|
name: Name of group to extract e.g. 'ref'
|
||||||
|
value: Raw string e.g. 'PO-ABC-1234'
|
||||||
|
fmt_string: Format pattern e.g. 'PO-???-{ref}
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: String value of the named group
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
ValueError: format string is incorrectly specified, or provided value does not match format string
|
||||||
|
NameError: named value does not exist in the format string
|
||||||
|
IndexError: named value could not be found in the provided entry
|
||||||
|
"""
|
||||||
|
|
||||||
|
info = parse_format_string(fmt_string)
|
||||||
|
|
||||||
|
if name not in info.keys():
|
||||||
|
raise NameError(_(f"Value '{name}' does not appear in pattern format"))
|
||||||
|
|
||||||
|
# Construct a regular expression for matching against the provided format string
|
||||||
|
# Note: This will raise a ValueError if 'fmt_string' is incorrectly specified
|
||||||
|
pattern = construct_format_regex(fmt_string)
|
||||||
|
|
||||||
|
# Run the regex matcher against the raw string
|
||||||
|
result = re.match(pattern, value)
|
||||||
|
|
||||||
|
if not result:
|
||||||
|
raise ValueError(_("Provided value does not match required pattern: ") + fmt_string)
|
||||||
|
|
||||||
|
# And return the value we are interested in
|
||||||
|
# Note: This will raise an IndexError if the named group was not matched
|
||||||
|
return result.group(name)
|
||||||
@@ -15,7 +15,6 @@ from allauth.account.forms import SignupForm, set_form_field_order
|
|||||||
from allauth.exceptions import ImmediateHttpResponse
|
from allauth.exceptions import ImmediateHttpResponse
|
||||||
from allauth.socialaccount.adapter import DefaultSocialAccountAdapter
|
from allauth.socialaccount.adapter import DefaultSocialAccountAdapter
|
||||||
from allauth_2fa.adapter import OTPAdapter
|
from allauth_2fa.adapter import OTPAdapter
|
||||||
from allauth_2fa.forms import TOTPDeviceRemoveForm
|
|
||||||
from allauth_2fa.utils import user_has_valid_totp_device
|
from allauth_2fa.utils import user_has_valid_totp_device
|
||||||
from crispy_forms.bootstrap import (AppendedText, PrependedAppendedText,
|
from crispy_forms.bootstrap import (AppendedText, PrependedAppendedText,
|
||||||
PrependedText)
|
PrependedText)
|
||||||
@@ -270,36 +269,3 @@ class CustomSocialAccountAdapter(RegistratonMixin, DefaultSocialAccountAdapter):
|
|||||||
|
|
||||||
# Otherwise defer to the original allauth adapter.
|
# Otherwise defer to the original allauth adapter.
|
||||||
return super().login(request, user)
|
return super().login(request, user)
|
||||||
|
|
||||||
|
|
||||||
# Temporary fix for django-allauth-2fa # TODO remove
|
|
||||||
# See https://github.com/inventree/InvenTree/security/advisories/GHSA-8j76-mm54-52xq
|
|
||||||
|
|
||||||
class CustomTOTPDeviceRemoveForm(TOTPDeviceRemoveForm):
|
|
||||||
"""Custom Form to ensure a token is provided before removing MFA"""
|
|
||||||
# User must input a valid token so 2FA can be removed
|
|
||||||
token = forms.CharField(
|
|
||||||
label=_('Token'),
|
|
||||||
)
|
|
||||||
|
|
||||||
def __init__(self, user, **kwargs):
|
|
||||||
"""Add token field."""
|
|
||||||
super().__init__(user, **kwargs)
|
|
||||||
self.fields['token'].widget.attrs.update(
|
|
||||||
{
|
|
||||||
'autofocus': 'autofocus',
|
|
||||||
'autocomplete': 'off',
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
def clean_token(self):
|
|
||||||
"""Ensure at least one valid token is provided."""
|
|
||||||
# Ensure that the user has provided a valid token
|
|
||||||
token = self.cleaned_data.get('token')
|
|
||||||
|
|
||||||
# Verify that the user has provided a valid token
|
|
||||||
for device in self.user.totpdevice_set.filter(confirmed=True):
|
|
||||||
if device.verify_token(token):
|
|
||||||
return token
|
|
||||||
|
|
||||||
raise forms.ValidationError(_("The entered token is not valid"))
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib.auth import get_user_model
|
from django.contrib.auth import get_user_model
|
||||||
@@ -19,7 +20,9 @@ from error_report.models import Error
|
|||||||
from mptt.exceptions import InvalidMove
|
from mptt.exceptions import InvalidMove
|
||||||
from mptt.models import MPTTModel, TreeForeignKey
|
from mptt.models import MPTTModel, TreeForeignKey
|
||||||
|
|
||||||
|
import InvenTree.format
|
||||||
import InvenTree.helpers
|
import InvenTree.helpers
|
||||||
|
from common.models import InvenTreeSetting
|
||||||
from InvenTree.fields import InvenTreeURLField
|
from InvenTree.fields import InvenTreeURLField
|
||||||
from InvenTree.validators import validate_tree_name
|
from InvenTree.validators import validate_tree_name
|
||||||
|
|
||||||
@@ -96,9 +99,6 @@ class DataImportMixin(object):
|
|||||||
class ReferenceIndexingMixin(models.Model):
|
class ReferenceIndexingMixin(models.Model):
|
||||||
"""A mixin for keeping track of numerical copies of the "reference" field.
|
"""A mixin for keeping track of numerical copies of the "reference" field.
|
||||||
|
|
||||||
!!DANGER!! always add `ReferenceIndexingSerializerMixin`to all your models serializers to
|
|
||||||
ensure the reference field is not too big
|
|
||||||
|
|
||||||
Here, we attempt to convert a "reference" field value (char) to an integer,
|
Here, we attempt to convert a "reference" field value (char) to an integer,
|
||||||
for performing fast natural sorting.
|
for performing fast natural sorting.
|
||||||
|
|
||||||
@@ -112,24 +112,216 @@ class ReferenceIndexingMixin(models.Model):
|
|||||||
- Otherwise, we store zero
|
- Otherwise, we store zero
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
# Name of the global setting which defines the required reference pattern for this model
|
||||||
|
REFERENCE_PATTERN_SETTING = None
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_reference_pattern(cls):
|
||||||
|
"""Returns the reference pattern associated with this model.
|
||||||
|
|
||||||
|
This is defined by a global setting object, specified by the REFERENCE_PATTERN_SETTING attribute
|
||||||
|
"""
|
||||||
|
|
||||||
|
# By default, we return an empty string
|
||||||
|
if cls.REFERENCE_PATTERN_SETTING is None:
|
||||||
|
return ''
|
||||||
|
|
||||||
|
return InvenTreeSetting.get_setting(cls.REFERENCE_PATTERN_SETTING, create=False).strip()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_reference_context(cls):
|
||||||
|
"""Generate context data for generating the 'reference' field for this class.
|
||||||
|
|
||||||
|
- Returns a python dict object which contains the context data for formatting the reference string.
|
||||||
|
- The default implementation provides some default context information
|
||||||
|
"""
|
||||||
|
|
||||||
|
return {
|
||||||
|
'ref': cls.get_next_reference(),
|
||||||
|
'date': datetime.now(),
|
||||||
|
}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_most_recent_item(cls):
|
||||||
|
"""Return the item which is 'most recent'
|
||||||
|
|
||||||
|
In practice, this means the item with the highest reference value
|
||||||
|
"""
|
||||||
|
|
||||||
|
query = cls.objects.all().order_by('-reference_int', '-pk')
|
||||||
|
|
||||||
|
if query.exists():
|
||||||
|
return query.first()
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_next_reference(cls):
|
||||||
|
"""Return the next available reference value for this particular class."""
|
||||||
|
|
||||||
|
# Find the "most recent" item
|
||||||
|
latest = cls.get_most_recent_item()
|
||||||
|
|
||||||
|
if not latest:
|
||||||
|
# No existing items
|
||||||
|
return 1
|
||||||
|
|
||||||
|
reference = latest.reference.strip
|
||||||
|
|
||||||
|
try:
|
||||||
|
reference = InvenTree.format.extract_named_group('ref', reference, cls.get_reference_pattern())
|
||||||
|
except Exception:
|
||||||
|
# If reference cannot be extracted using the pattern, try just the integer value
|
||||||
|
reference = str(latest.reference_int)
|
||||||
|
|
||||||
|
# Attempt to perform 'intelligent' incrementing of the reference field
|
||||||
|
incremented = InvenTree.helpers.increment(reference)
|
||||||
|
|
||||||
|
try:
|
||||||
|
incremented = int(incremented)
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
return incremented
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def generate_reference(cls):
|
||||||
|
"""Generate the next 'reference' field based on specified pattern"""
|
||||||
|
|
||||||
|
fmt = cls.get_reference_pattern()
|
||||||
|
ctx = cls.get_reference_context()
|
||||||
|
|
||||||
|
reference = None
|
||||||
|
|
||||||
|
attempts = set()
|
||||||
|
|
||||||
|
while reference is None:
|
||||||
|
try:
|
||||||
|
ref = fmt.format(**ctx)
|
||||||
|
|
||||||
|
if ref in attempts:
|
||||||
|
# We are stuck in a loop!
|
||||||
|
reference = ref
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
attempts.add(ref)
|
||||||
|
|
||||||
|
if cls.objects.filter(reference=ref).exists():
|
||||||
|
# Handle case where we have duplicated an existing reference
|
||||||
|
ctx['ref'] = InvenTree.helpers.increment(ctx['ref'])
|
||||||
|
else:
|
||||||
|
# We have found an 'unused' reference
|
||||||
|
reference = ref
|
||||||
|
break
|
||||||
|
|
||||||
|
except Exception:
|
||||||
|
# If anything goes wrong, return the most recent reference
|
||||||
|
recent = cls.get_most_recent_item()
|
||||||
|
if recent:
|
||||||
|
reference = recent.reference
|
||||||
|
else:
|
||||||
|
reference = ""
|
||||||
|
|
||||||
|
return reference
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def validate_reference_pattern(cls, pattern):
|
||||||
|
"""Ensure that the provided pattern is valid"""
|
||||||
|
|
||||||
|
ctx = cls.get_reference_context()
|
||||||
|
|
||||||
|
try:
|
||||||
|
info = InvenTree.format.parse_format_string(pattern)
|
||||||
|
except Exception:
|
||||||
|
raise ValidationError({
|
||||||
|
"value": _("Improperly formatted pattern"),
|
||||||
|
})
|
||||||
|
|
||||||
|
# Check that only 'allowed' keys are provided
|
||||||
|
for key in info.keys():
|
||||||
|
if key not in ctx.keys():
|
||||||
|
raise ValidationError({
|
||||||
|
"value": _("Unknown format key specified") + f": '{key}'"
|
||||||
|
})
|
||||||
|
|
||||||
|
# Check that the 'ref' variable is specified
|
||||||
|
if 'ref' not in info.keys():
|
||||||
|
raise ValidationError({
|
||||||
|
'value': _("Missing required format key") + ": 'ref'"
|
||||||
|
})
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def validate_reference_field(cls, value):
|
||||||
|
"""Check that the provided 'reference' value matches the requisite pattern"""
|
||||||
|
|
||||||
|
pattern = cls.get_reference_pattern()
|
||||||
|
|
||||||
|
value = str(value).strip()
|
||||||
|
|
||||||
|
if len(value) == 0:
|
||||||
|
raise ValidationError(_("Reference field cannot be empty"))
|
||||||
|
|
||||||
|
# An 'empty' pattern means no further validation is required
|
||||||
|
if not pattern:
|
||||||
|
return
|
||||||
|
|
||||||
|
if not InvenTree.format.validate_string(value, pattern):
|
||||||
|
raise ValidationError(_("Reference must match required pattern") + ": " + pattern)
|
||||||
|
|
||||||
|
# Check that the reference field can be rebuild
|
||||||
|
cls.rebuild_reference_field(value, validate=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
"""Metaclass options. Abstract ensures no database table is created."""
|
"""Metaclass options. Abstract ensures no database table is created."""
|
||||||
|
|
||||||
abstract = True
|
abstract = True
|
||||||
|
|
||||||
def rebuild_reference_field(self):
|
@classmethod
|
||||||
"""Extract integer out of reference for sorting."""
|
def rebuild_reference_field(cls, reference, validate=False):
|
||||||
reference = getattr(self, 'reference', '')
|
"""Extract integer out of reference for sorting.
|
||||||
self.reference_int = extract_int(reference)
|
|
||||||
|
If the 'integer' portion is buried somewhere 'within' the reference,
|
||||||
|
we can first try to extract it using the pattern.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
reference - BO-123-ABC
|
||||||
|
pattern - BO-{ref}-???
|
||||||
|
extracted - 123
|
||||||
|
|
||||||
|
If we cannot extract using the pattern for some reason, fallback to the entire reference
|
||||||
|
"""
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Extract named group based on provided pattern
|
||||||
|
reference = InvenTree.format.extract_named_group('ref', reference, cls.get_reference_pattern())
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
reference_int = extract_int(reference)
|
||||||
|
|
||||||
|
if validate:
|
||||||
|
if reference_int > models.BigIntegerField.MAX_BIGINT:
|
||||||
|
raise ValidationError({
|
||||||
|
"reference": _("Reference number is too large")
|
||||||
|
})
|
||||||
|
|
||||||
|
return reference_int
|
||||||
|
|
||||||
reference_int = models.BigIntegerField(default=0)
|
reference_int = models.BigIntegerField(default=0)
|
||||||
|
|
||||||
|
|
||||||
def extract_int(reference, clip=0x7fffffff):
|
def extract_int(reference, clip=0x7fffffff, allow_negative=False):
|
||||||
"""Extract integer out of reference."""
|
"""Extract an integer out of reference."""
|
||||||
|
|
||||||
# Default value if we cannot convert to an integer
|
# Default value if we cannot convert to an integer
|
||||||
ref_int = 0
|
ref_int = 0
|
||||||
|
|
||||||
|
reference = str(reference).strip()
|
||||||
|
|
||||||
|
# Ignore empty string
|
||||||
|
if len(reference) == 0:
|
||||||
|
return 0
|
||||||
|
|
||||||
# Look at the start of the string - can it be "integerized"?
|
# Look at the start of the string - can it be "integerized"?
|
||||||
result = re.match(r"^(\d+)", reference)
|
result = re.match(r"^(\d+)", reference)
|
||||||
|
|
||||||
@@ -139,6 +331,16 @@ def extract_int(reference, clip=0x7fffffff):
|
|||||||
ref_int = int(ref)
|
ref_int = int(ref)
|
||||||
except Exception:
|
except Exception:
|
||||||
ref_int = 0
|
ref_int = 0
|
||||||
|
else:
|
||||||
|
# Look at the "end" of the string
|
||||||
|
result = re.search(r'(\d+)$', reference)
|
||||||
|
|
||||||
|
if result and len(result.groups()) == 1:
|
||||||
|
ref = result.groups()[0]
|
||||||
|
try:
|
||||||
|
ref_int = int(ref)
|
||||||
|
except Exception:
|
||||||
|
ref_int = 0
|
||||||
|
|
||||||
# Ensure that the returned values are within the range that can be stored in an IntegerField
|
# Ensure that the returned values are within the range that can be stored in an IntegerField
|
||||||
# Note: This will result in large values being "clipped"
|
# Note: This will result in large values being "clipped"
|
||||||
@@ -148,6 +350,9 @@ def extract_int(reference, clip=0x7fffffff):
|
|||||||
elif ref_int < -clip:
|
elif ref_int < -clip:
|
||||||
ref_int = -clip
|
ref_int = -clip
|
||||||
|
|
||||||
|
if not allow_negative and ref_int < 0:
|
||||||
|
ref_int = abs(ref_int)
|
||||||
|
|
||||||
return ref_int
|
return ref_int
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ from decimal import Decimal
|
|||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.core.exceptions import ValidationError as DjangoValidationError
|
from django.core.exceptions import ValidationError as DjangoValidationError
|
||||||
from django.db import models
|
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
|
||||||
import tablib
|
import tablib
|
||||||
@@ -20,8 +19,6 @@ from rest_framework.fields import empty
|
|||||||
from rest_framework.serializers import DecimalField
|
from rest_framework.serializers import DecimalField
|
||||||
from rest_framework.utils import model_meta
|
from rest_framework.utils import model_meta
|
||||||
|
|
||||||
from .models import extract_int
|
|
||||||
|
|
||||||
|
|
||||||
class InvenTreeMoneySerializer(MoneyField):
|
class InvenTreeMoneySerializer(MoneyField):
|
||||||
"""Custom serializer for 'MoneyField', which ensures that passed values are numerically valid.
|
"""Custom serializer for 'MoneyField', which ensures that passed values are numerically valid.
|
||||||
@@ -211,16 +208,6 @@ class UserSerializer(InvenTreeModelSerializer):
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class ReferenceIndexingSerializerMixin():
|
|
||||||
"""This serializer mixin ensures the the reference is not to big / small for the BigIntegerField."""
|
|
||||||
|
|
||||||
def validate_reference(self, value):
|
|
||||||
"""Ensures the reference is not to big / small for the BigIntegerField."""
|
|
||||||
if extract_int(value) > models.BigIntegerField.MAX_BIGINT:
|
|
||||||
raise serializers.ValidationError('reference is to to big')
|
|
||||||
return value
|
|
||||||
|
|
||||||
|
|
||||||
class InvenTreeAttachmentSerializerField(serializers.FileField):
|
class InvenTreeAttachmentSerializerField(serializers.FileField):
|
||||||
"""Override the DRF native FileField serializer, to remove the leading server path.
|
"""Override the DRF native FileField serializer, to remove the leading server path.
|
||||||
|
|
||||||
|
|||||||
+2
-2
File diff suppressed because one or more lines are too long
@@ -40,8 +40,7 @@ function attachClipboard(selector, containerselector, textElement) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// create Clipboard
|
// create Clipboard
|
||||||
// eslint-disable-next-line no-unused-vars
|
new ClipboardJS(selector, {
|
||||||
var cis = new ClipboardJS(selector, {
|
|
||||||
text: text,
|
text: text,
|
||||||
container: containerselector
|
container: containerselector
|
||||||
});
|
});
|
||||||
@@ -110,6 +109,9 @@ function inventreeDocReady() {
|
|||||||
$('#launch-about').click(function() {
|
$('#launch-about').click(function() {
|
||||||
launchModalForm(`/about/`, {
|
launchModalForm(`/about/`, {
|
||||||
no_post: true,
|
no_post: true,
|
||||||
|
after_render: function() {
|
||||||
|
attachClipboard('.clip-btn', 'modal-form');
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ from djmoney.contrib.exchange.exceptions import MissingRate
|
|||||||
from djmoney.contrib.exchange.models import Rate, convert_money
|
from djmoney.contrib.exchange.models import Rate, convert_money
|
||||||
from djmoney.money import Money
|
from djmoney.money import Money
|
||||||
|
|
||||||
|
import InvenTree.format
|
||||||
import InvenTree.tasks
|
import InvenTree.tasks
|
||||||
from common.models import InvenTreeSetting
|
from common.models import InvenTreeSetting
|
||||||
from common.settings import currency_codes
|
from common.settings import currency_codes
|
||||||
@@ -60,6 +61,137 @@ class ValidatorTest(TestCase):
|
|||||||
validate_overage("aaaa")
|
validate_overage("aaaa")
|
||||||
|
|
||||||
|
|
||||||
|
class FormatTest(TestCase):
|
||||||
|
"""Unit tests for custom string formatting functionality"""
|
||||||
|
|
||||||
|
def test_parse(self):
|
||||||
|
"""Tests for the 'parse_format_string' function"""
|
||||||
|
|
||||||
|
# Extract data from a valid format string
|
||||||
|
fmt = "PO-{abc:02f}-{ref:04d}-{date}-???"
|
||||||
|
|
||||||
|
info = InvenTree.format.parse_format_string(fmt)
|
||||||
|
|
||||||
|
self.assertIn('abc', info)
|
||||||
|
self.assertIn('ref', info)
|
||||||
|
self.assertIn('date', info)
|
||||||
|
|
||||||
|
# Try with invalid strings
|
||||||
|
for fmt in [
|
||||||
|
'PO-{{xyz}',
|
||||||
|
'PO-{xyz}}',
|
||||||
|
'PO-{xyz}-{',
|
||||||
|
]:
|
||||||
|
|
||||||
|
with self.assertRaises(ValueError):
|
||||||
|
InvenTree.format.parse_format_string(fmt)
|
||||||
|
|
||||||
|
def test_create_regex(self):
|
||||||
|
"""Test function for creating a regex from a format string"""
|
||||||
|
|
||||||
|
tests = {
|
||||||
|
"PO-123-{ref:04f}": r"^PO\-123\-(?P<ref>.+)$",
|
||||||
|
"{PO}-???-{ref}-{date}-22": r"^(?P<PO>.+)\-...\-(?P<ref>.+)\-(?P<date>.+)\-22$",
|
||||||
|
"ABC-123-###-{ref}": r"^ABC\-123\-\d\d\d\-(?P<ref>.+)$",
|
||||||
|
"ABC-123": r"^ABC\-123$",
|
||||||
|
}
|
||||||
|
|
||||||
|
for fmt, reg in tests.items():
|
||||||
|
self.assertEqual(InvenTree.format.construct_format_regex(fmt), reg)
|
||||||
|
|
||||||
|
def test_validate_format(self):
|
||||||
|
"""Test that string validation works as expected"""
|
||||||
|
|
||||||
|
# These tests should pass
|
||||||
|
for value, pattern in {
|
||||||
|
"ABC-hello-123": "???-{q}-###",
|
||||||
|
"BO-1234": "BO-{ref}",
|
||||||
|
"111.222.fred.china": "???.###.{name}.{place}",
|
||||||
|
"PO-1234": "PO-{ref:04d}"
|
||||||
|
}.items():
|
||||||
|
self.assertTrue(InvenTree.format.validate_string(value, pattern))
|
||||||
|
|
||||||
|
# These tests should fail
|
||||||
|
for value, pattern in {
|
||||||
|
"ABC-hello-123": "###-{q}-???",
|
||||||
|
"BO-1234": "BO.{ref}",
|
||||||
|
"BO-####": "BO-{pattern}-{next}",
|
||||||
|
"BO-123d": "BO-{ref:04d}"
|
||||||
|
}.items():
|
||||||
|
self.assertFalse(InvenTree.format.validate_string(value, pattern))
|
||||||
|
|
||||||
|
def test_extract_value(self):
|
||||||
|
"""Test that we can extract named values based on a format string"""
|
||||||
|
|
||||||
|
# Simple tests based on a straight-forward format string
|
||||||
|
fmt = "PO-###-{ref:04d}"
|
||||||
|
|
||||||
|
tests = {
|
||||||
|
"123": "PO-123-123",
|
||||||
|
"456": "PO-123-456",
|
||||||
|
"789": "PO-123-789",
|
||||||
|
}
|
||||||
|
|
||||||
|
for k, v in tests.items():
|
||||||
|
self.assertEqual(InvenTree.format.extract_named_group('ref', v, fmt), k)
|
||||||
|
|
||||||
|
# However these ones should fail
|
||||||
|
tests = {
|
||||||
|
'abc': 'PO-123-abc',
|
||||||
|
'xyz': 'PO-123-xyz',
|
||||||
|
}
|
||||||
|
|
||||||
|
for v in tests.values():
|
||||||
|
with self.assertRaises(ValueError):
|
||||||
|
InvenTree.format.extract_named_group('ref', v, fmt)
|
||||||
|
|
||||||
|
# More complex tests
|
||||||
|
fmt = "PO-{date}-{test}-???-{ref}-###"
|
||||||
|
val = "PO-2022-02-01-hello-ABC-12345-222"
|
||||||
|
|
||||||
|
data = {
|
||||||
|
'date': '2022-02-01',
|
||||||
|
'test': 'hello',
|
||||||
|
'ref': '12345',
|
||||||
|
}
|
||||||
|
|
||||||
|
for k, v in data.items():
|
||||||
|
self.assertEqual(InvenTree.format.extract_named_group(k, val, fmt), v)
|
||||||
|
|
||||||
|
# Test for error conditions
|
||||||
|
|
||||||
|
# Raises a ValueError as the format string is bad
|
||||||
|
with self.assertRaises(ValueError):
|
||||||
|
InvenTree.format.extract_named_group(
|
||||||
|
"test",
|
||||||
|
"PO-1234-5",
|
||||||
|
"PO-{test}-{"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Raises a NameError as the named group does not exist in the format string
|
||||||
|
with self.assertRaises(NameError):
|
||||||
|
InvenTree.format.extract_named_group(
|
||||||
|
"missing",
|
||||||
|
"PO-12345",
|
||||||
|
"PO-{test}",
|
||||||
|
)
|
||||||
|
|
||||||
|
# Raises a ValueError as the value does not match the format string
|
||||||
|
with self.assertRaises(ValueError):
|
||||||
|
InvenTree.format.extract_named_group(
|
||||||
|
"test",
|
||||||
|
"PO-1234",
|
||||||
|
"PO-{test}-1234",
|
||||||
|
)
|
||||||
|
|
||||||
|
with self.assertRaises(ValueError):
|
||||||
|
InvenTree.format.extract_named_group(
|
||||||
|
"test",
|
||||||
|
"PO-ABC-xyz",
|
||||||
|
"PO-###-{test}",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class TestHelpers(TestCase):
|
class TestHelpers(TestCase):
|
||||||
"""Tests for InvenTree helper functions."""
|
"""Tests for InvenTree helper functions."""
|
||||||
|
|
||||||
|
|||||||
@@ -57,17 +57,6 @@ def validate_part_ipn(value):
|
|||||||
raise ValidationError(_('IPN must match regex pattern {pat}').format(pat=pattern))
|
raise ValidationError(_('IPN must match regex pattern {pat}').format(pat=pattern))
|
||||||
|
|
||||||
|
|
||||||
def validate_build_order_reference(value):
|
|
||||||
"""Validate the 'reference' field of a BuildOrder."""
|
|
||||||
pattern = common.models.InvenTreeSetting.get_setting('BUILDORDER_REFERENCE_REGEX')
|
|
||||||
|
|
||||||
if pattern:
|
|
||||||
match = re.search(pattern, value)
|
|
||||||
|
|
||||||
if match is None:
|
|
||||||
raise ValidationError(_('Reference must match pattern {pattern}').format(pattern=pattern))
|
|
||||||
|
|
||||||
|
|
||||||
def validate_purchase_order_reference(value):
|
def validate_purchase_order_reference(value):
|
||||||
"""Validate the 'reference' field of a PurchaseOrder."""
|
"""Validate the 'reference' field of a PurchaseOrder."""
|
||||||
pattern = common.models.InvenTreeSetting.get_setting('PURCHASEORDER_REFERENCE_REGEX')
|
pattern = common.models.InvenTreeSetting.get_setting('PURCHASEORDER_REFERENCE_REGEX')
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ from common.settings import currency_code_default, currency_codes
|
|||||||
from part.models import PartCategory
|
from part.models import PartCategory
|
||||||
from users.models import RuleSet, check_user_role
|
from users.models import RuleSet, check_user_role
|
||||||
|
|
||||||
from .forms import CustomTOTPDeviceRemoveForm, EditUserForm, SetPasswordForm
|
from .forms import EditUserForm, SetPasswordForm
|
||||||
|
|
||||||
|
|
||||||
def auth_request(request):
|
def auth_request(request):
|
||||||
@@ -764,10 +764,8 @@ class NotificationsView(TemplateView):
|
|||||||
template_name = "InvenTree/notifications/notifications.html"
|
template_name = "InvenTree/notifications/notifications.html"
|
||||||
|
|
||||||
|
|
||||||
# Temporary fix for django-allauth-2fa # TODO remove
|
# Custom 2FA removal form to allow custom redirect URL
|
||||||
# See https://github.com/inventree/InvenTree/security/advisories/GHSA-8j76-mm54-52xq
|
|
||||||
|
|
||||||
class CustomTwoFactorRemove(TwoFactorRemove):
|
class CustomTwoFactorRemove(TwoFactorRemove):
|
||||||
"""Use custom form."""
|
"""Specify custom URL redirect."""
|
||||||
form_class = CustomTOTPDeviceRemoveForm
|
|
||||||
success_url = reverse_lazy("settings")
|
success_url = reverse_lazy("settings")
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
fields:
|
fields:
|
||||||
part: 100 # Build against part 100 "Bob"
|
part: 100 # Build against part 100 "Bob"
|
||||||
batch: 'B1'
|
batch: 'B1'
|
||||||
reference: "0001"
|
reference: "BO-0001"
|
||||||
title: 'Building 7 parts'
|
title: 'Building 7 parts'
|
||||||
quantity: 7
|
quantity: 7
|
||||||
notes: 'Some simple notes'
|
notes: 'Some simple notes'
|
||||||
@@ -21,7 +21,7 @@
|
|||||||
pk: 2
|
pk: 2
|
||||||
fields:
|
fields:
|
||||||
part: 50
|
part: 50
|
||||||
reference: "0002"
|
reference: "BO-0002"
|
||||||
title: 'Making things'
|
title: 'Making things'
|
||||||
batch: 'B2'
|
batch: 'B2'
|
||||||
status: 40 # COMPLETE
|
status: 40 # COMPLETE
|
||||||
@@ -37,7 +37,7 @@
|
|||||||
pk: 3
|
pk: 3
|
||||||
fields:
|
fields:
|
||||||
part: 50
|
part: 50
|
||||||
reference: "0003"
|
reference: "BO-003"
|
||||||
title: 'Making things'
|
title: 'Making things'
|
||||||
batch: 'B2'
|
batch: 'B2'
|
||||||
status: 40 # COMPLETE
|
status: 40 # COMPLETE
|
||||||
@@ -53,7 +53,7 @@
|
|||||||
pk: 4
|
pk: 4
|
||||||
fields:
|
fields:
|
||||||
part: 50
|
part: 50
|
||||||
reference: "0004"
|
reference: "BO-4"
|
||||||
title: 'Making things'
|
title: 'Making things'
|
||||||
batch: 'B4'
|
batch: 'B4'
|
||||||
status: 40 # COMPLETE
|
status: 40 # COMPLETE
|
||||||
@@ -69,7 +69,7 @@
|
|||||||
pk: 5
|
pk: 5
|
||||||
fields:
|
fields:
|
||||||
part: 25
|
part: 25
|
||||||
reference: "0005"
|
reference: "BO-0005"
|
||||||
title: "Building some Widgets"
|
title: "Building some Widgets"
|
||||||
batch: "B10"
|
batch: "B10"
|
||||||
status: 40 # Complete
|
status: 40 # Complete
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Generated by Django 3.0.7 on 2020-10-19 13:02
|
# Generated by Django 3.0.7 on 2020-10-19 13:02
|
||||||
|
|
||||||
import InvenTree.validators
|
import build.validators
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
@@ -18,6 +18,6 @@ class Migration(migrations.Migration):
|
|||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='build',
|
model_name='build',
|
||||||
name='reference',
|
name='reference',
|
||||||
field=models.CharField(help_text='Build Order Reference', max_length=64, unique=True, validators=[InvenTree.validators.validate_build_order_reference], verbose_name='Reference'),
|
field=models.CharField(help_text='Build Order Reference', max_length=64, unique=True, validators=[build.validators.validate_build_order_reference], verbose_name='Reference'),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Generated by Django 3.2.4 on 2021-07-08 14:14
|
# Generated by Django 3.2.4 on 2021-07-08 14:14
|
||||||
|
|
||||||
import InvenTree.validators
|
import build.validators
|
||||||
import build.models
|
import build.models
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
|
||||||
@@ -15,6 +15,6 @@ class Migration(migrations.Migration):
|
|||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='build',
|
model_name='build',
|
||||||
name='reference',
|
name='reference',
|
||||||
field=models.CharField(default=build.models.get_next_build_number, help_text='Build Order Reference', max_length=64, unique=True, validators=[InvenTree.validators.validate_build_order_reference], verbose_name='Reference'),
|
field=models.CharField(default=build.validators.generate_next_build_reference, help_text='Build Order Reference', max_length=64, unique=True, validators=[build.validators.validate_build_order_reference], verbose_name='Reference'),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -0,0 +1,69 @@
|
|||||||
|
# Generated by Django 3.2.14 on 2022-07-07 11:01
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
def update_build_reference(apps, schema_editor):
|
||||||
|
"""Update the build order reference.
|
||||||
|
|
||||||
|
Ref: https://github.com/inventree/InvenTree/pull/3267
|
||||||
|
|
||||||
|
Performs the following steps:
|
||||||
|
- Extract existing 'prefix' value
|
||||||
|
- Generate a build order pattern based on the prefix value
|
||||||
|
- Update any existing build order references with the specified prefix
|
||||||
|
"""
|
||||||
|
|
||||||
|
InvenTreeSetting = apps.get_model('common', 'inventreesetting')
|
||||||
|
|
||||||
|
try:
|
||||||
|
prefix = InvenTreeSetting.objects.get(key='BUILDORDER_REFERENCE_PREFIX').value
|
||||||
|
except Exception:
|
||||||
|
prefix = 'BO-'
|
||||||
|
|
||||||
|
# Construct a reference pattern
|
||||||
|
pattern = prefix + '{ref:04d}'
|
||||||
|
|
||||||
|
# Create or update the BuildOrder.reference pattern
|
||||||
|
try:
|
||||||
|
setting = InvenTreeSetting.objects.get(key='BUILDORDER_REFERENCE_PATTERN')
|
||||||
|
setting.value = pattern
|
||||||
|
setting.save()
|
||||||
|
except InvenTreeSetting.DoesNotExist:
|
||||||
|
setting = InvenTreeSetting.objects.create(
|
||||||
|
key='BUILDORDER_REFERENCE_PATTERN',
|
||||||
|
value=pattern,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Update any existing build order references with the prefix
|
||||||
|
Build = apps.get_model('build', 'build')
|
||||||
|
|
||||||
|
n = 0
|
||||||
|
|
||||||
|
for build in Build.objects.all():
|
||||||
|
if not build.reference.startswith(prefix):
|
||||||
|
build.reference = prefix + build.reference
|
||||||
|
build.save()
|
||||||
|
n += 1
|
||||||
|
|
||||||
|
if n > 0:
|
||||||
|
print(f"Updated reference field for {n} BuildOrder objects")
|
||||||
|
|
||||||
|
|
||||||
|
def nupdate_build_reference(apps, schema_editor):
|
||||||
|
"""Reverse migration code. Does nothing."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('build', '0035_alter_build_notes'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RunPython(
|
||||||
|
update_build_reference,
|
||||||
|
reverse_code=nupdate_build_reference,
|
||||||
|
)
|
||||||
|
]
|
||||||
+17
-36
@@ -22,12 +22,14 @@ from mptt.exceptions import InvalidMove
|
|||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
|
||||||
from InvenTree.status_codes import BuildStatus, StockStatus, StockHistoryCode
|
from InvenTree.status_codes import BuildStatus, StockStatus, StockHistoryCode
|
||||||
from InvenTree.helpers import increment, getSetting, normalize, MakeBarcode, notify_responsible
|
from InvenTree.helpers import increment, normalize, MakeBarcode, notify_responsible
|
||||||
from InvenTree.models import InvenTreeAttachment, ReferenceIndexingMixin
|
from InvenTree.models import InvenTreeAttachment, ReferenceIndexingMixin
|
||||||
from InvenTree.validators import validate_build_order_reference
|
|
||||||
|
from build.validators import generate_next_build_reference, validate_build_order_reference
|
||||||
|
|
||||||
import InvenTree.fields
|
import InvenTree.fields
|
||||||
import InvenTree.helpers
|
import InvenTree.helpers
|
||||||
|
import InvenTree.ready
|
||||||
import InvenTree.tasks
|
import InvenTree.tasks
|
||||||
|
|
||||||
from plugin.events import trigger_event
|
from plugin.events import trigger_event
|
||||||
@@ -38,32 +40,6 @@ from stock import models as StockModels
|
|||||||
from users import models as UserModels
|
from users import models as UserModels
|
||||||
|
|
||||||
|
|
||||||
def get_next_build_number():
|
|
||||||
"""Returns the next available BuildOrder reference number."""
|
|
||||||
if Build.objects.count() == 0:
|
|
||||||
return '0001'
|
|
||||||
|
|
||||||
build = Build.objects.exclude(reference=None).last()
|
|
||||||
|
|
||||||
attempts = {build.reference}
|
|
||||||
|
|
||||||
reference = build.reference
|
|
||||||
|
|
||||||
while 1:
|
|
||||||
reference = increment(reference)
|
|
||||||
|
|
||||||
if reference in attempts:
|
|
||||||
# Escape infinite recursion
|
|
||||||
return reference
|
|
||||||
|
|
||||||
if Build.objects.filter(reference=reference).exists():
|
|
||||||
attempts.add(reference)
|
|
||||||
else:
|
|
||||||
break
|
|
||||||
|
|
||||||
return reference
|
|
||||||
|
|
||||||
|
|
||||||
class Build(MPTTModel, ReferenceIndexingMixin):
|
class Build(MPTTModel, ReferenceIndexingMixin):
|
||||||
"""A Build object organises the creation of new StockItem objects from other existing StockItem objects.
|
"""A Build object organises the creation of new StockItem objects from other existing StockItem objects.
|
||||||
|
|
||||||
@@ -89,6 +65,9 @@ class Build(MPTTModel, ReferenceIndexingMixin):
|
|||||||
|
|
||||||
OVERDUE_FILTER = Q(status__in=BuildStatus.ACTIVE_CODES) & ~Q(target_date=None) & Q(target_date__lte=datetime.now().date())
|
OVERDUE_FILTER = Q(status__in=BuildStatus.ACTIVE_CODES) & ~Q(target_date=None) & Q(target_date__lte=datetime.now().date())
|
||||||
|
|
||||||
|
# Global setting for specifying reference pattern
|
||||||
|
REFERENCE_PATTERN_SETTING = 'BUILDORDER_REFERENCE_PATTERN'
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_api_url():
|
def get_api_url():
|
||||||
"""Return the API URL associated with the BuildOrder model"""
|
"""Return the API URL associated with the BuildOrder model"""
|
||||||
@@ -106,7 +85,7 @@ class Build(MPTTModel, ReferenceIndexingMixin):
|
|||||||
def api_defaults(cls, request):
|
def api_defaults(cls, request):
|
||||||
"""Return default values for this model when issuing an API OPTIONS request."""
|
"""Return default values for this model when issuing an API OPTIONS request."""
|
||||||
defaults = {
|
defaults = {
|
||||||
'reference': get_next_build_number(),
|
'reference': generate_next_build_reference(),
|
||||||
}
|
}
|
||||||
|
|
||||||
if request and request.user:
|
if request and request.user:
|
||||||
@@ -116,7 +95,8 @@ class Build(MPTTModel, ReferenceIndexingMixin):
|
|||||||
|
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
"""Custom save method for the BuildOrder model"""
|
"""Custom save method for the BuildOrder model"""
|
||||||
self.rebuild_reference_field()
|
self.validate_reference_field(self.reference)
|
||||||
|
self.reference_int = self.rebuild_reference_field(self.reference)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
super().save(*args, **kwargs)
|
super().save(*args, **kwargs)
|
||||||
@@ -172,9 +152,7 @@ class Build(MPTTModel, ReferenceIndexingMixin):
|
|||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
"""String representation of a BuildOrder"""
|
"""String representation of a BuildOrder"""
|
||||||
prefix = getSetting("BUILDORDER_REFERENCE_PREFIX")
|
return self.reference
|
||||||
|
|
||||||
return f"{prefix}{self.reference}"
|
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
"""Return the web URL associated with this BuildOrder"""
|
"""Return the web URL associated with this BuildOrder"""
|
||||||
@@ -186,9 +164,9 @@ class Build(MPTTModel, ReferenceIndexingMixin):
|
|||||||
blank=False,
|
blank=False,
|
||||||
help_text=_('Build Order Reference'),
|
help_text=_('Build Order Reference'),
|
||||||
verbose_name=_('Reference'),
|
verbose_name=_('Reference'),
|
||||||
default=get_next_build_number,
|
default=generate_next_build_reference,
|
||||||
validators=[
|
validators=[
|
||||||
validate_build_order_reference
|
validate_build_order_reference,
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -199,7 +177,6 @@ class Build(MPTTModel, ReferenceIndexingMixin):
|
|||||||
help_text=_('Brief description of the build')
|
help_text=_('Brief description of the build')
|
||||||
)
|
)
|
||||||
|
|
||||||
# TODO - Perhaps delete the build "tree"
|
|
||||||
parent = TreeForeignKey(
|
parent = TreeForeignKey(
|
||||||
'self',
|
'self',
|
||||||
on_delete=models.SET_NULL,
|
on_delete=models.SET_NULL,
|
||||||
@@ -1092,6 +1069,10 @@ class Build(MPTTModel, ReferenceIndexingMixin):
|
|||||||
@receiver(post_save, sender=Build, dispatch_uid='build_post_save_log')
|
@receiver(post_save, sender=Build, dispatch_uid='build_post_save_log')
|
||||||
def after_save_build(sender, instance: Build, created: bool, **kwargs):
|
def after_save_build(sender, instance: Build, created: bool, **kwargs):
|
||||||
"""Callback function to be executed after a Build instance is saved."""
|
"""Callback function to be executed after a Build instance is saved."""
|
||||||
|
# Escape if we are importing data
|
||||||
|
if InvenTree.ready.isImportingData() or not InvenTree.ready.canAppAccessDatabase(allow_test=True):
|
||||||
|
return
|
||||||
|
|
||||||
from . import tasks as build_tasks
|
from . import tasks as build_tasks
|
||||||
|
|
||||||
if created:
|
if created:
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ from rest_framework import serializers
|
|||||||
from rest_framework.serializers import ValidationError
|
from rest_framework.serializers import ValidationError
|
||||||
|
|
||||||
from InvenTree.serializers import InvenTreeModelSerializer, InvenTreeAttachmentSerializer
|
from InvenTree.serializers import InvenTreeModelSerializer, InvenTreeAttachmentSerializer
|
||||||
from InvenTree.serializers import ReferenceIndexingSerializerMixin, UserSerializer
|
from InvenTree.serializers import UserSerializer
|
||||||
|
|
||||||
import InvenTree.helpers
|
import InvenTree.helpers
|
||||||
from InvenTree.helpers import extract_serial_numbers
|
from InvenTree.helpers import extract_serial_numbers
|
||||||
@@ -28,7 +28,7 @@ from users.serializers import OwnerSerializer
|
|||||||
from .models import Build, BuildItem, BuildOrderAttachment
|
from .models import Build, BuildItem, BuildOrderAttachment
|
||||||
|
|
||||||
|
|
||||||
class BuildSerializer(ReferenceIndexingSerializerMixin, InvenTreeModelSerializer):
|
class BuildSerializer(InvenTreeModelSerializer):
|
||||||
"""Serializes a Build object."""
|
"""Serializes a Build object."""
|
||||||
|
|
||||||
url = serializers.CharField(source='get_absolute_url', read_only=True)
|
url = serializers.CharField(source='get_absolute_url', read_only=True)
|
||||||
@@ -74,6 +74,16 @@ class BuildSerializer(ReferenceIndexingSerializerMixin, InvenTreeModelSerializer
|
|||||||
if part_detail is not True:
|
if part_detail is not True:
|
||||||
self.fields.pop('part_detail')
|
self.fields.pop('part_detail')
|
||||||
|
|
||||||
|
reference = serializers.CharField(required=True)
|
||||||
|
|
||||||
|
def validate_reference(self, reference):
|
||||||
|
"""Custom validation for the Build reference field"""
|
||||||
|
|
||||||
|
# Ensure the reference matches the required pattern
|
||||||
|
Build.validate_reference_field(reference)
|
||||||
|
|
||||||
|
return reference
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
"""Serializer metaclass"""
|
"""Serializer metaclass"""
|
||||||
model = Build
|
model = Build
|
||||||
|
|||||||
@@ -748,6 +748,7 @@ class BuildListTest(BuildAPITest):
|
|||||||
|
|
||||||
Build.objects.create(
|
Build.objects.create(
|
||||||
part=part,
|
part=part,
|
||||||
|
reference="BO-0006",
|
||||||
quantity=10,
|
quantity=10,
|
||||||
title='Just some thing',
|
title='Just some thing',
|
||||||
status=BuildStatus.PRODUCTION,
|
status=BuildStatus.PRODUCTION,
|
||||||
@@ -773,20 +774,23 @@ class BuildListTest(BuildAPITest):
|
|||||||
Build.objects.create(
|
Build.objects.create(
|
||||||
part=part,
|
part=part,
|
||||||
quantity=10,
|
quantity=10,
|
||||||
reference=f"build-000{i}",
|
reference=f"BO-{i + 10}",
|
||||||
title=f"Sub build {i}",
|
title=f"Sub build {i}",
|
||||||
parent=parent
|
parent=parent
|
||||||
)
|
)
|
||||||
|
|
||||||
# And some sub-sub builds
|
# And some sub-sub builds
|
||||||
for sub_build in Build.objects.filter(parent=parent):
|
for ii, sub_build in enumerate(Build.objects.filter(parent=parent)):
|
||||||
|
|
||||||
for i in range(3):
|
for i in range(3):
|
||||||
|
|
||||||
|
x = ii * 10 + i + 50
|
||||||
|
|
||||||
Build.objects.create(
|
Build.objects.create(
|
||||||
part=part,
|
part=part,
|
||||||
reference=f"{sub_build.reference}-00{i}-sub",
|
reference=f"BO-{x}",
|
||||||
|
title=f"{sub_build.reference}-00{i}-sub",
|
||||||
quantity=40,
|
quantity=40,
|
||||||
title=f"sub sub build {i}",
|
|
||||||
parent=sub_build
|
parent=sub_build
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ from InvenTree import status_codes as status
|
|||||||
|
|
||||||
import common.models
|
import common.models
|
||||||
import build.tasks
|
import build.tasks
|
||||||
from build.models import Build, BuildItem, get_next_build_number
|
from build.models import Build, BuildItem, generate_next_build_reference
|
||||||
from part.models import Part, BomItem, BomItemSubstitute
|
from part.models import Part, BomItem, BomItemSubstitute
|
||||||
from stock.models import StockItem
|
from stock.models import StockItem
|
||||||
from users.models import Owner
|
from users.models import Owner
|
||||||
@@ -88,7 +88,7 @@ class BuildTestBase(TestCase):
|
|||||||
quantity=2
|
quantity=2
|
||||||
)
|
)
|
||||||
|
|
||||||
ref = get_next_build_number()
|
ref = generate_next_build_reference()
|
||||||
|
|
||||||
# Create a "Build" object to make 10x objects
|
# Create a "Build" object to make 10x objects
|
||||||
self.build = Build.objects.create(
|
self.build = Build.objects.create(
|
||||||
@@ -133,20 +133,97 @@ class BuildTest(BuildTestBase):
|
|||||||
def test_ref_int(self):
|
def test_ref_int(self):
|
||||||
"""Test the "integer reference" field used for natural sorting"""
|
"""Test the "integer reference" field used for natural sorting"""
|
||||||
|
|
||||||
for ii in range(10):
|
common.models.InvenTreeSetting.set_setting('BUILDORDER_REFERENCE_PATTERN', 'BO-{ref}-???', change_user=None)
|
||||||
|
|
||||||
|
refs = {
|
||||||
|
'BO-123-456': 123,
|
||||||
|
'BO-456-123': 456,
|
||||||
|
'BO-999-ABC': 999,
|
||||||
|
'BO-123ABC-ABC': 123,
|
||||||
|
'BO-ABC123-ABC': 123,
|
||||||
|
}
|
||||||
|
|
||||||
|
for ref, ref_int in refs.items():
|
||||||
build = Build(
|
build = Build(
|
||||||
reference=f"{ii}_abcde",
|
reference=ref,
|
||||||
quantity=1,
|
quantity=1,
|
||||||
part=self.assembly,
|
part=self.assembly,
|
||||||
title="Making some parts"
|
title='Making some parts',
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assertEqual(build.reference_int, 0)
|
self.assertEqual(build.reference_int, 0)
|
||||||
|
|
||||||
build.save()
|
build.save()
|
||||||
|
self.assertEqual(build.reference_int, ref_int)
|
||||||
|
|
||||||
# After saving, the integer reference should have been updated
|
def test_ref_validation(self):
|
||||||
self.assertEqual(build.reference_int, ii)
|
"""Test that the reference field validation works as expected"""
|
||||||
|
|
||||||
|
# Default reference pattern = 'BO-{ref:04d}
|
||||||
|
|
||||||
|
# These patterns should fail
|
||||||
|
for ref in [
|
||||||
|
'BO-1234x',
|
||||||
|
'BO1234',
|
||||||
|
'OB-1234',
|
||||||
|
'BO--1234'
|
||||||
|
]:
|
||||||
|
with self.assertRaises(ValidationError):
|
||||||
|
Build.objects.create(
|
||||||
|
part=self.assembly,
|
||||||
|
quantity=10,
|
||||||
|
reference=ref,
|
||||||
|
title='Invalid reference',
|
||||||
|
)
|
||||||
|
|
||||||
|
for ref in [
|
||||||
|
'BO-1234',
|
||||||
|
'BO-9999',
|
||||||
|
'BO-123'
|
||||||
|
]:
|
||||||
|
Build.objects.create(
|
||||||
|
part=self.assembly,
|
||||||
|
quantity=10,
|
||||||
|
reference=ref,
|
||||||
|
title='Valid reference',
|
||||||
|
)
|
||||||
|
|
||||||
|
# Try a new validator pattern
|
||||||
|
common.models.InvenTreeSetting.set_setting('BUILDORDER_REFERENCE_PATTERN', '{ref}-BO', change_user=None)
|
||||||
|
|
||||||
|
for ref in [
|
||||||
|
'1234-BO',
|
||||||
|
'9999-BO'
|
||||||
|
]:
|
||||||
|
Build.objects.create(
|
||||||
|
part=self.assembly,
|
||||||
|
quantity=10,
|
||||||
|
reference=ref,
|
||||||
|
title='Valid reference',
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_next_ref(self):
|
||||||
|
"""Test that the next reference is automatically generated"""
|
||||||
|
|
||||||
|
common.models.InvenTreeSetting.set_setting('BUILDORDER_REFERENCE_PATTERN', 'XYZ-{ref:06d}', change_user=None)
|
||||||
|
|
||||||
|
build = Build.objects.create(
|
||||||
|
part=self.assembly,
|
||||||
|
quantity=5,
|
||||||
|
reference='XYZ-987',
|
||||||
|
title='Some thing',
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(build.reference_int, 987)
|
||||||
|
|
||||||
|
# Now create one *without* specifying the reference
|
||||||
|
build = Build.objects.create(
|
||||||
|
part=self.assembly,
|
||||||
|
quantity=1,
|
||||||
|
title='Some new title',
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(build.reference, 'XYZ-000988')
|
||||||
|
self.assertEqual(build.reference_int, 988)
|
||||||
|
|
||||||
def test_init(self):
|
def test_init(self):
|
||||||
"""Perform some basic tests before we start the ball rolling"""
|
"""Perform some basic tests before we start the ball rolling"""
|
||||||
@@ -404,7 +481,7 @@ class BuildTest(BuildTestBase):
|
|||||||
"""Test that a notification is sent when a new build is created"""
|
"""Test that a notification is sent when a new build is created"""
|
||||||
|
|
||||||
Build.objects.create(
|
Build.objects.create(
|
||||||
reference='IIIII',
|
reference='BO-9999',
|
||||||
title='Some new build',
|
title='Some new build',
|
||||||
part=self.assembly,
|
part=self.assembly,
|
||||||
quantity=5,
|
quantity=5,
|
||||||
|
|||||||
@@ -104,3 +104,57 @@ class TestReferenceMigration(MigratorTestCase):
|
|||||||
# Check that the build reference is properly assigned
|
# Check that the build reference is properly assigned
|
||||||
for build in Build.objects.all():
|
for build in Build.objects.all():
|
||||||
self.assertEqual(str(build.reference), str(build.pk))
|
self.assertEqual(str(build.reference), str(build.pk))
|
||||||
|
|
||||||
|
|
||||||
|
class TestReferencePatternMigration(MigratorTestCase):
|
||||||
|
"""Unit test for data migration which converts reference to new format.
|
||||||
|
|
||||||
|
Ref: https://github.com/inventree/InvenTree/pull/3267
|
||||||
|
"""
|
||||||
|
|
||||||
|
migrate_from = ('build', '0019_auto_20201019_1302')
|
||||||
|
migrate_to = ('build', helpers.getNewestMigrationFile('build'))
|
||||||
|
|
||||||
|
def prepare(self):
|
||||||
|
"""Create some initial data prior to migration"""
|
||||||
|
|
||||||
|
Setting = self.old_state.apps.get_model('common', 'inventreesetting')
|
||||||
|
|
||||||
|
# Create a custom existing prefix so we can confirm the operation is working
|
||||||
|
Setting.objects.create(
|
||||||
|
key='BUILDORDER_REFERENCE_PREFIX',
|
||||||
|
value='BuildOrder-',
|
||||||
|
)
|
||||||
|
|
||||||
|
Part = self.old_state.apps.get_model('part', 'part')
|
||||||
|
|
||||||
|
assembly = Part.objects.create(
|
||||||
|
name='Assy 1',
|
||||||
|
description='An assembly',
|
||||||
|
level=0, lft=0, rght=0, tree_id=0,
|
||||||
|
)
|
||||||
|
|
||||||
|
Build = self.old_state.apps.get_model('build', 'build')
|
||||||
|
|
||||||
|
for idx in range(1, 11):
|
||||||
|
Build.objects.create(
|
||||||
|
part=assembly,
|
||||||
|
title=f"Build {idx}",
|
||||||
|
quantity=idx,
|
||||||
|
reference=f"{idx + 100}",
|
||||||
|
level=0, lft=0, rght=0, tree_id=0,
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_reference_migration(self):
|
||||||
|
"""Test that the reference fields have been correctly updated"""
|
||||||
|
|
||||||
|
Build = self.new_state.apps.get_model('build', 'build')
|
||||||
|
|
||||||
|
for build in Build.objects.all():
|
||||||
|
self.assertTrue(build.reference.startswith('BuildOrder-'))
|
||||||
|
|
||||||
|
Setting = self.new_state.apps.get_model('common', 'inventreesetting')
|
||||||
|
|
||||||
|
pattern = Setting.objects.get(key='BUILDORDER_REFERENCE_PATTERN')
|
||||||
|
|
||||||
|
self.assertEqual(pattern.value, 'BuildOrder-{ref:04d}')
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ class BuildTestSimple(InvenTreeTestCase):
|
|||||||
self.assertEqual(b.batch, 'B2')
|
self.assertEqual(b.batch, 'B2')
|
||||||
self.assertEqual(b.quantity, 21)
|
self.assertEqual(b.quantity, 21)
|
||||||
|
|
||||||
self.assertEqual(str(b), 'BO0002')
|
self.assertEqual(str(b), 'BO-0002')
|
||||||
|
|
||||||
def test_url(self):
|
def test_url(self):
|
||||||
"""Test URL lookup"""
|
"""Test URL lookup"""
|
||||||
@@ -75,11 +75,6 @@ class BuildTestSimple(InvenTreeTestCase):
|
|||||||
self.assertEqual(b1.is_active, True)
|
self.assertEqual(b1.is_active, True)
|
||||||
self.assertEqual(b2.is_active, False)
|
self.assertEqual(b2.is_active, False)
|
||||||
|
|
||||||
def test_required_parts(self):
|
|
||||||
"""Test set of required BOM items for the build"""
|
|
||||||
# TODO: Generate BOM for test part
|
|
||||||
...
|
|
||||||
|
|
||||||
def test_cancel_build(self):
|
def test_cancel_build(self):
|
||||||
"""Test build cancellation function."""
|
"""Test build cancellation function."""
|
||||||
build = Build.objects.get(id=1)
|
build = Build.objects.get(id=1)
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
"""Validation methods for the build app"""
|
||||||
|
|
||||||
|
|
||||||
|
def generate_next_build_reference():
|
||||||
|
"""Generate the next available BuildOrder reference"""
|
||||||
|
|
||||||
|
from build.models import Build
|
||||||
|
|
||||||
|
return Build.generate_reference()
|
||||||
|
|
||||||
|
|
||||||
|
def validate_build_order_reference_pattern(pattern):
|
||||||
|
"""Validate the BuildOrder reference 'pattern' setting"""
|
||||||
|
|
||||||
|
from build.models import Build
|
||||||
|
|
||||||
|
Build.validate_reference_pattern(pattern)
|
||||||
|
|
||||||
|
|
||||||
|
def validate_build_order_reference(value):
|
||||||
|
"""Validate that the BuildOrder reference field matches the required pattern"""
|
||||||
|
|
||||||
|
from build.models import Build
|
||||||
|
|
||||||
|
Build.validate_reference_field(value)
|
||||||
+28
-17
@@ -36,10 +36,12 @@ from djmoney.contrib.exchange.models import convert_money
|
|||||||
from djmoney.settings import CURRENCY_CHOICES
|
from djmoney.settings import CURRENCY_CHOICES
|
||||||
from rest_framework.exceptions import PermissionDenied
|
from rest_framework.exceptions import PermissionDenied
|
||||||
|
|
||||||
|
import build.validators
|
||||||
import InvenTree.fields
|
import InvenTree.fields
|
||||||
import InvenTree.helpers
|
import InvenTree.helpers
|
||||||
import InvenTree.ready
|
import InvenTree.ready
|
||||||
import InvenTree.validators
|
import InvenTree.validators
|
||||||
|
import order.validators
|
||||||
|
|
||||||
logger = logging.getLogger('inventree')
|
logger = logging.getLogger('inventree')
|
||||||
|
|
||||||
@@ -341,6 +343,10 @@ class BaseInvenTreeSetting(models.Model):
|
|||||||
# Unless otherwise specified, attempt to create the setting
|
# Unless otherwise specified, attempt to create the setting
|
||||||
create = kwargs.get('create', True)
|
create = kwargs.get('create', True)
|
||||||
|
|
||||||
|
# Prevent creation of new settings objects when importing data
|
||||||
|
if InvenTree.ready.isImportingData() or not InvenTree.ready.canAppAccessDatabase(allow_test=True):
|
||||||
|
create = False
|
||||||
|
|
||||||
if create:
|
if create:
|
||||||
# Attempt to create a new settings object
|
# Attempt to create a new settings object
|
||||||
setting = cls(
|
setting = cls(
|
||||||
@@ -850,6 +856,13 @@ class InvenTreeSetting(BaseInvenTreeSetting):
|
|||||||
'default': False,
|
'default': False,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
'INVENTREE_REQUIRE_CONFIRM': {
|
||||||
|
'name': _('Require confirm'),
|
||||||
|
'description': _('Require explicit user confirmation for certain action.'),
|
||||||
|
'validator': bool,
|
||||||
|
'default': True,
|
||||||
|
},
|
||||||
|
|
||||||
'BARCODE_ENABLE': {
|
'BARCODE_ENABLE': {
|
||||||
'name': _('Barcode Support'),
|
'name': _('Barcode Support'),
|
||||||
'description': _('Enable barcode scanner support'),
|
'description': _('Enable barcode scanner support'),
|
||||||
@@ -1132,21 +1145,18 @@ class InvenTreeSetting(BaseInvenTreeSetting):
|
|||||||
'validator': bool,
|
'validator': bool,
|
||||||
},
|
},
|
||||||
|
|
||||||
'BUILDORDER_REFERENCE_PREFIX': {
|
'BUILDORDER_REFERENCE_PATTERN': {
|
||||||
'name': _('Build Order Reference Prefix'),
|
'name': _('Build Order Reference Pattern'),
|
||||||
'description': _('Prefix value for build order reference'),
|
'description': _('Required pattern for generating Build Order reference field'),
|
||||||
'default': 'BO',
|
'default': 'BO-{ref:04d}',
|
||||||
|
'validator': build.validators.validate_build_order_reference_pattern,
|
||||||
},
|
},
|
||||||
|
|
||||||
'BUILDORDER_REFERENCE_REGEX': {
|
'SALESORDER_REFERENCE_PATTERN': {
|
||||||
'name': _('Build Order Reference Regex'),
|
'name': _('Sales Order Reference Pattern'),
|
||||||
'description': _('Regular expression pattern for matching build order reference')
|
'description': _('Required pattern for generating Sales Order reference field'),
|
||||||
},
|
'default': 'SO-{ref:04d}',
|
||||||
|
'validator': order.validators.validate_sales_order_reference_pattern,
|
||||||
'SALESORDER_REFERENCE_PREFIX': {
|
|
||||||
'name': _('Sales Order Reference Prefix'),
|
|
||||||
'description': _('Prefix value for sales order reference'),
|
|
||||||
'default': 'SO',
|
|
||||||
},
|
},
|
||||||
|
|
||||||
'SALESORDER_DEFAULT_SHIPMENT': {
|
'SALESORDER_DEFAULT_SHIPMENT': {
|
||||||
@@ -1156,10 +1166,11 @@ class InvenTreeSetting(BaseInvenTreeSetting):
|
|||||||
'validator': bool,
|
'validator': bool,
|
||||||
},
|
},
|
||||||
|
|
||||||
'PURCHASEORDER_REFERENCE_PREFIX': {
|
'PURCHASEORDER_REFERENCE_PATTERN': {
|
||||||
'name': _('Purchase Order Reference Prefix'),
|
'name': _('Purchase Order Reference Pattern'),
|
||||||
'description': _('Prefix value for purchase order reference'),
|
'description': _('Required pattern for generating Purchase Order reference field'),
|
||||||
'default': 'PO',
|
'default': 'PO-{ref:04d}',
|
||||||
|
'validator': order.validators.validate_purchase_order_reference_pattern,
|
||||||
},
|
},
|
||||||
|
|
||||||
# login / SSO
|
# login / SSO
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -8,7 +8,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2022-06-28 12:13+0000\n"
|
"POT-Creation-Date: 2022-07-04 02:07+0000\n"
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
@@ -141,7 +141,7 @@ msgstr ""
|
|||||||
|
|
||||||
#: InvenTree/models.py:191 stock/models.py:2096
|
#: InvenTree/models.py:191 stock/models.py:2096
|
||||||
#: templates/js/translated/attachment.js:103
|
#: templates/js/translated/attachment.js:103
|
||||||
#: templates/js/translated/attachment.js:239
|
#: templates/js/translated/attachment.js:240
|
||||||
msgid "Attachment"
|
msgid "Attachment"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -165,7 +165,7 @@ msgid "Link to external URL"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: InvenTree/models.py:202 templates/js/translated/attachment.js:104
|
#: InvenTree/models.py:202 templates/js/translated/attachment.js:104
|
||||||
#: templates/js/translated/attachment.js:283
|
#: templates/js/translated/attachment.js:284
|
||||||
msgid "Comment"
|
msgid "Comment"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -243,7 +243,7 @@ msgstr ""
|
|||||||
#: stock/templates/stock/location.html:103
|
#: stock/templates/stock/location.html:103
|
||||||
#: templates/InvenTree/settings/plugin_settings.html:33
|
#: templates/InvenTree/settings/plugin_settings.html:33
|
||||||
#: templates/js/translated/bom.js:553 templates/js/translated/bom.js:845
|
#: templates/js/translated/bom.js:553 templates/js/translated/bom.js:845
|
||||||
#: templates/js/translated/build.js:2475 templates/js/translated/company.js:397
|
#: templates/js/translated/build.js:2476 templates/js/translated/company.js:397
|
||||||
#: templates/js/translated/company.js:653
|
#: templates/js/translated/company.js:653
|
||||||
#: templates/js/translated/company.js:944 templates/js/translated/order.js:1656
|
#: templates/js/translated/company.js:944 templates/js/translated/order.js:1656
|
||||||
#: templates/js/translated/order.js:1888 templates/js/translated/order.js:2476
|
#: templates/js/translated/order.js:1888 templates/js/translated/order.js:2476
|
||||||
@@ -656,7 +656,7 @@ msgstr ""
|
|||||||
#: report/templates/report/inventree_build_order_base.html:106
|
#: report/templates/report/inventree_build_order_base.html:106
|
||||||
#: templates/email/build_order_completed.html:16
|
#: templates/email/build_order_completed.html:16
|
||||||
#: templates/email/overdue_build_order.html:15
|
#: templates/email/overdue_build_order.html:15
|
||||||
#: templates/js/translated/build.js:727
|
#: templates/js/translated/build.js:728
|
||||||
msgid "Build Order"
|
msgid "Build Order"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -680,7 +680,7 @@ msgstr ""
|
|||||||
#: report/templates/report/inventree_po_report.html:91
|
#: report/templates/report/inventree_po_report.html:91
|
||||||
#: report/templates/report/inventree_so_report.html:92
|
#: report/templates/report/inventree_so_report.html:92
|
||||||
#: templates/js/translated/bom.js:690 templates/js/translated/bom.js:852
|
#: templates/js/translated/bom.js:690 templates/js/translated/bom.js:852
|
||||||
#: templates/js/translated/build.js:1776 templates/js/translated/order.js:1919
|
#: templates/js/translated/build.js:1777 templates/js/translated/order.js:1919
|
||||||
#: templates/js/translated/order.js:2120 templates/js/translated/order.js:3468
|
#: templates/js/translated/order.js:2120 templates/js/translated/order.js:3468
|
||||||
#: templates/js/translated/order.js:3976
|
#: templates/js/translated/order.js:3976
|
||||||
msgid "Reference"
|
msgid "Reference"
|
||||||
@@ -719,8 +719,8 @@ msgstr ""
|
|||||||
#: templates/email/overdue_build_order.html:16
|
#: templates/email/overdue_build_order.html:16
|
||||||
#: templates/js/translated/barcode.js:435 templates/js/translated/bom.js:552
|
#: templates/js/translated/barcode.js:435 templates/js/translated/bom.js:552
|
||||||
#: templates/js/translated/bom.js:689 templates/js/translated/bom.js:799
|
#: templates/js/translated/bom.js:689 templates/js/translated/bom.js:799
|
||||||
#: templates/js/translated/build.js:1153 templates/js/translated/build.js:1646
|
#: templates/js/translated/build.js:1154 templates/js/translated/build.js:1647
|
||||||
#: templates/js/translated/build.js:2082 templates/js/translated/build.js:2480
|
#: templates/js/translated/build.js:2083 templates/js/translated/build.js:2481
|
||||||
#: templates/js/translated/company.js:255
|
#: templates/js/translated/company.js:255
|
||||||
#: templates/js/translated/company.js:484
|
#: templates/js/translated/company.js:484
|
||||||
#: templates/js/translated/company.js:594
|
#: templates/js/translated/company.js:594
|
||||||
@@ -748,8 +748,8 @@ msgstr ""
|
|||||||
msgid "SalesOrder to which this build is allocated"
|
msgid "SalesOrder to which this build is allocated"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/models.py:236 build/serializers.py:758
|
#: build/models.py:236 build/serializers.py:774
|
||||||
#: templates/js/translated/build.js:2070 templates/js/translated/order.js:2818
|
#: templates/js/translated/build.js:2071 templates/js/translated/order.js:2818
|
||||||
msgid "Source Location"
|
msgid "Source Location"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -812,7 +812,7 @@ msgid "Target date for build completion. Build will be overdue after this date."
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/models.py:289 order/models.py:323
|
#: build/models.py:289 order/models.py:323
|
||||||
#: templates/js/translated/build.js:2557
|
#: templates/js/translated/build.js:2558
|
||||||
msgid "Completion Date"
|
msgid "Completion Date"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -820,7 +820,7 @@ msgstr ""
|
|||||||
msgid "completed by"
|
msgid "completed by"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/models.py:303 templates/js/translated/build.js:2525
|
#: build/models.py:303 templates/js/translated/build.js:2526
|
||||||
msgid "Issued by"
|
msgid "Issued by"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -833,7 +833,7 @@ msgstr ""
|
|||||||
#: order/templates/order/order_base.html:176
|
#: order/templates/order/order_base.html:176
|
||||||
#: order/templates/order/sales_order_base.html:183 part/models.py:935
|
#: order/templates/order/sales_order_base.html:183 part/models.py:935
|
||||||
#: report/templates/report/inventree_build_order_base.html:159
|
#: report/templates/report/inventree_build_order_base.html:159
|
||||||
#: templates/js/translated/build.js:2537 templates/js/translated/order.js:1690
|
#: templates/js/translated/build.js:2538 templates/js/translated/order.js:1690
|
||||||
msgid "Responsible"
|
msgid "Responsible"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -874,48 +874,48 @@ msgstr ""
|
|||||||
msgid "Build output does not match Build Order"
|
msgid "Build output does not match Build Order"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/models.py:1148
|
#: build/models.py:1162
|
||||||
msgid "Build item must specify a build output, as master part is marked as trackable"
|
msgid "Build item must specify a build output, as master part is marked as trackable"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/models.py:1157
|
#: build/models.py:1171
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Allocated quantity ({q}) must not exceed available stock quantity ({a})"
|
msgid "Allocated quantity ({q}) must not exceed available stock quantity ({a})"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/models.py:1167
|
#: build/models.py:1181
|
||||||
msgid "Stock item is over-allocated"
|
msgid "Stock item is over-allocated"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/models.py:1173 order/models.py:1404
|
#: build/models.py:1187 order/models.py:1404
|
||||||
msgid "Allocation quantity must be greater than zero"
|
msgid "Allocation quantity must be greater than zero"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/models.py:1179
|
#: build/models.py:1193
|
||||||
msgid "Quantity must be 1 for serialized stock"
|
msgid "Quantity must be 1 for serialized stock"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/models.py:1236
|
#: build/models.py:1250
|
||||||
msgid "Selected stock item not found in BOM"
|
msgid "Selected stock item not found in BOM"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/models.py:1305 stock/templates/stock/item_base.html:177
|
#: build/models.py:1319 stock/templates/stock/item_base.html:177
|
||||||
#: templates/InvenTree/search.html:137 templates/js/translated/build.js:2453
|
#: templates/InvenTree/search.html:137 templates/js/translated/build.js:2454
|
||||||
#: templates/navbar.html:38
|
#: templates/navbar.html:38
|
||||||
msgid "Build"
|
msgid "Build"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/models.py:1306
|
#: build/models.py:1320
|
||||||
msgid "Build to allocate parts"
|
msgid "Build to allocate parts"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/models.py:1322 build/serializers.py:603 order/serializers.py:996
|
#: build/models.py:1336 build/serializers.py:619 order/serializers.py:996
|
||||||
#: order/serializers.py:1017 stock/serializers.py:394 stock/serializers.py:741
|
#: order/serializers.py:1017 stock/serializers.py:394 stock/serializers.py:741
|
||||||
#: stock/serializers.py:867 stock/templates/stock/item_base.html:10
|
#: stock/serializers.py:867 stock/templates/stock/item_base.html:10
|
||||||
#: stock/templates/stock/item_base.html:23
|
#: stock/templates/stock/item_base.html:23
|
||||||
#: stock/templates/stock/item_base.html:199
|
#: stock/templates/stock/item_base.html:199
|
||||||
#: templates/js/translated/build.js:738 templates/js/translated/build.js:743
|
#: templates/js/translated/build.js:739 templates/js/translated/build.js:744
|
||||||
#: templates/js/translated/build.js:2084 templates/js/translated/build.js:2642
|
#: templates/js/translated/build.js:2085 templates/js/translated/build.js:2643
|
||||||
#: templates/js/translated/order.js:101 templates/js/translated/order.js:2831
|
#: templates/js/translated/order.js:101 templates/js/translated/order.js:2831
|
||||||
#: templates/js/translated/order.js:3135 templates/js/translated/order.js:3140
|
#: templates/js/translated/order.js:3135 templates/js/translated/order.js:3140
|
||||||
#: templates/js/translated/order.js:3235 templates/js/translated/order.js:3325
|
#: templates/js/translated/order.js:3235 templates/js/translated/order.js:3325
|
||||||
@@ -924,11 +924,11 @@ msgstr ""
|
|||||||
msgid "Stock Item"
|
msgid "Stock Item"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/models.py:1323
|
#: build/models.py:1337
|
||||||
msgid "Source stock item"
|
msgid "Source stock item"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/models.py:1335 build/serializers.py:183
|
#: build/models.py:1349 build/serializers.py:183
|
||||||
#: build/templates/build/build_base.html:82
|
#: build/templates/build/build_base.html:82
|
||||||
#: build/templates/build/detail.html:34 common/models.py:1644
|
#: build/templates/build/detail.html:34 common/models.py:1644
|
||||||
#: company/forms.py:36 company/templates/company/supplier_part.html:279
|
#: company/forms.py:36 company/templates/company/supplier_part.html:279
|
||||||
@@ -947,10 +947,10 @@ msgstr ""
|
|||||||
#: stock/templates/stock/item_base.html:300
|
#: stock/templates/stock/item_base.html:300
|
||||||
#: templates/email/build_order_completed.html:18
|
#: templates/email/build_order_completed.html:18
|
||||||
#: templates/js/translated/barcode.js:437 templates/js/translated/bom.js:691
|
#: templates/js/translated/barcode.js:437 templates/js/translated/bom.js:691
|
||||||
#: templates/js/translated/bom.js:860 templates/js/translated/build.js:422
|
#: templates/js/translated/bom.js:860 templates/js/translated/build.js:423
|
||||||
#: templates/js/translated/build.js:574 templates/js/translated/build.js:765
|
#: templates/js/translated/build.js:575 templates/js/translated/build.js:766
|
||||||
#: templates/js/translated/build.js:1175 templates/js/translated/build.js:1672
|
#: templates/js/translated/build.js:1176 templates/js/translated/build.js:1673
|
||||||
#: templates/js/translated/build.js:2085
|
#: templates/js/translated/build.js:2086
|
||||||
#: templates/js/translated/model_renderers.js:120
|
#: templates/js/translated/model_renderers.js:120
|
||||||
#: templates/js/translated/order.js:117 templates/js/translated/order.js:886
|
#: templates/js/translated/order.js:117 templates/js/translated/order.js:886
|
||||||
#: templates/js/translated/order.js:1925 templates/js/translated/order.js:2126
|
#: templates/js/translated/order.js:1925 templates/js/translated/order.js:2126
|
||||||
@@ -965,20 +965,20 @@ msgstr ""
|
|||||||
msgid "Quantity"
|
msgid "Quantity"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/models.py:1336
|
#: build/models.py:1350
|
||||||
msgid "Stock quantity to allocate to build"
|
msgid "Stock quantity to allocate to build"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/models.py:1344
|
#: build/models.py:1358
|
||||||
msgid "Install into"
|
msgid "Install into"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/models.py:1345
|
#: build/models.py:1359
|
||||||
msgid "Destination stock item"
|
msgid "Destination stock item"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/serializers.py:128 build/serializers.py:632
|
#: build/serializers.py:128 build/serializers.py:648
|
||||||
#: templates/js/translated/build.js:1163
|
#: templates/js/translated/build.js:1164
|
||||||
msgid "Build Output"
|
msgid "Build Output"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -1002,7 +1002,7 @@ msgstr ""
|
|||||||
msgid "Enter quantity for build output"
|
msgid "Enter quantity for build output"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/serializers.py:198 build/serializers.py:623 order/models.py:355
|
#: build/serializers.py:198 build/serializers.py:639 order/models.py:355
|
||||||
#: order/serializers.py:280 order/serializers.py:435 part/serializers.py:503
|
#: order/serializers.py:280 order/serializers.py:435 part/serializers.py:503
|
||||||
#: part/serializers.py:926 stock/models.py:478 stock/models.py:1244
|
#: part/serializers.py:926 stock/models.py:478 stock/models.py:1244
|
||||||
#: stock/serializers.py:300
|
#: stock/serializers.py:300
|
||||||
@@ -1048,8 +1048,8 @@ msgstr ""
|
|||||||
#: stock/serializers.py:902 stock/serializers.py:1135
|
#: stock/serializers.py:902 stock/serializers.py:1135
|
||||||
#: stock/templates/stock/item_base.html:390
|
#: stock/templates/stock/item_base.html:390
|
||||||
#: templates/js/translated/barcode.js:436
|
#: templates/js/translated/barcode.js:436
|
||||||
#: templates/js/translated/barcode.js:618 templates/js/translated/build.js:750
|
#: templates/js/translated/barcode.js:618 templates/js/translated/build.js:751
|
||||||
#: templates/js/translated/build.js:1684 templates/js/translated/order.js:1213
|
#: templates/js/translated/build.js:1685 templates/js/translated/order.js:1213
|
||||||
#: templates/js/translated/order.js:3147 templates/js/translated/order.js:3250
|
#: templates/js/translated/order.js:3147 templates/js/translated/order.js:3250
|
||||||
#: templates/js/translated/order.js:3258 templates/js/translated/order.js:3339
|
#: templates/js/translated/order.js:3258 templates/js/translated/order.js:3339
|
||||||
#: templates/js/translated/part.js:181 templates/js/translated/stock.js:584
|
#: templates/js/translated/part.js:181 templates/js/translated/stock.js:584
|
||||||
@@ -1065,7 +1065,7 @@ msgstr ""
|
|||||||
#: build/serializers.py:363 build/templates/build/build_base.html:142
|
#: build/serializers.py:363 build/templates/build/build_base.html:142
|
||||||
#: build/templates/build/detail.html:62 order/models.py:665
|
#: build/templates/build/detail.html:62 order/models.py:665
|
||||||
#: order/serializers.py:458 stock/templates/stock/item_base.html:423
|
#: order/serializers.py:458 stock/templates/stock/item_base.html:423
|
||||||
#: templates/js/translated/barcode.js:182 templates/js/translated/build.js:2509
|
#: templates/js/translated/barcode.js:182 templates/js/translated/build.js:2510
|
||||||
#: templates/js/translated/order.js:1320 templates/js/translated/order.js:1660
|
#: templates/js/translated/order.js:1320 templates/js/translated/order.js:1660
|
||||||
#: templates/js/translated/order.js:2481 templates/js/translated/stock.js:1825
|
#: templates/js/translated/order.js:2481 templates/js/translated/stock.js:1825
|
||||||
#: templates/js/translated/stock.js:2530 templates/js/translated/stock.js:2662
|
#: templates/js/translated/stock.js:2530 templates/js/translated/stock.js:2662
|
||||||
@@ -1097,104 +1097,116 @@ msgid "Delete any build outputs which have not been completed"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/serializers.py:470
|
#: build/serializers.py:470
|
||||||
msgid "Accept Unallocated"
|
msgid "Accept Overallocated"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/serializers.py:471
|
#: build/serializers.py:471
|
||||||
msgid "Accept that stock items have not been fully allocated to this build order"
|
msgid "Accept stock items which have been overallocated to this build order"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/serializers.py:481 templates/js/translated/build.js:195
|
#: build/serializers.py:481
|
||||||
msgid "Required stock has not been fully allocated"
|
msgid "Some stock items have been overallocated"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/serializers.py:486
|
#: build/serializers.py:486
|
||||||
msgid "Accept Incomplete"
|
msgid "Accept Unallocated"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/serializers.py:487
|
#: build/serializers.py:487
|
||||||
|
msgid "Accept that stock items have not been fully allocated to this build order"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: build/serializers.py:497 templates/js/translated/build.js:196
|
||||||
|
msgid "Required stock has not been fully allocated"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: build/serializers.py:502
|
||||||
|
msgid "Accept Incomplete"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: build/serializers.py:503
|
||||||
msgid "Accept that the required number of build outputs have not been completed"
|
msgid "Accept that the required number of build outputs have not been completed"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/serializers.py:497 templates/js/translated/build.js:199
|
#: build/serializers.py:513 templates/js/translated/build.js:200
|
||||||
msgid "Required build quantity has not been completed"
|
msgid "Required build quantity has not been completed"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/serializers.py:506
|
#: build/serializers.py:522
|
||||||
msgid "Build order has incomplete outputs"
|
msgid "Build order has incomplete outputs"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/serializers.py:509 build/templates/build/build_base.html:95
|
#: build/serializers.py:525 build/templates/build/build_base.html:95
|
||||||
msgid "No build outputs have been created for this build order"
|
msgid "No build outputs have been created for this build order"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/serializers.py:535 build/serializers.py:580 part/models.py:2719
|
#: build/serializers.py:551 build/serializers.py:596 part/models.py:2719
|
||||||
#: part/models.py:2853
|
#: part/models.py:2853
|
||||||
msgid "BOM Item"
|
msgid "BOM Item"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/serializers.py:545
|
#: build/serializers.py:561
|
||||||
msgid "Build output"
|
msgid "Build output"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/serializers.py:553
|
#: build/serializers.py:569
|
||||||
msgid "Build output must point to the same build"
|
msgid "Build output must point to the same build"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/serializers.py:594
|
#: build/serializers.py:610
|
||||||
msgid "bom_item.part must point to the same part as the build order"
|
msgid "bom_item.part must point to the same part as the build order"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/serializers.py:609 stock/serializers.py:754
|
#: build/serializers.py:625 stock/serializers.py:754
|
||||||
msgid "Item must be in stock"
|
msgid "Item must be in stock"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/serializers.py:667 order/serializers.py:1054
|
#: build/serializers.py:683 order/serializers.py:1054
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Available quantity ({q}) exceeded"
|
msgid "Available quantity ({q}) exceeded"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/serializers.py:673
|
#: build/serializers.py:689
|
||||||
msgid "Build output must be specified for allocation of tracked parts"
|
msgid "Build output must be specified for allocation of tracked parts"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/serializers.py:680
|
#: build/serializers.py:696
|
||||||
msgid "Build output cannot be specified for allocation of untracked parts"
|
msgid "Build output cannot be specified for allocation of untracked parts"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/serializers.py:685
|
#: build/serializers.py:701
|
||||||
msgid "This stock item has already been allocated to this build output"
|
msgid "This stock item has already been allocated to this build output"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/serializers.py:708 order/serializers.py:1300
|
#: build/serializers.py:724 order/serializers.py:1300
|
||||||
msgid "Allocation items must be provided"
|
msgid "Allocation items must be provided"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/serializers.py:759
|
#: build/serializers.py:775
|
||||||
msgid "Stock location where parts are to be sourced (leave blank to take from any location)"
|
msgid "Stock location where parts are to be sourced (leave blank to take from any location)"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/serializers.py:767
|
#: build/serializers.py:783
|
||||||
msgid "Exclude Location"
|
msgid "Exclude Location"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/serializers.py:768
|
#: build/serializers.py:784
|
||||||
msgid "Exclude stock items from this selected location"
|
msgid "Exclude stock items from this selected location"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/serializers.py:773
|
#: build/serializers.py:789
|
||||||
msgid "Interchangeable Stock"
|
msgid "Interchangeable Stock"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/serializers.py:774
|
#: build/serializers.py:790
|
||||||
msgid "Stock items in multiple locations can be used interchangeably"
|
msgid "Stock items in multiple locations can be used interchangeably"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/serializers.py:779
|
#: build/serializers.py:795
|
||||||
msgid "Substitute Stock"
|
msgid "Substitute Stock"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/serializers.py:780
|
#: build/serializers.py:796
|
||||||
msgid "Allow allocation of substitute parts"
|
msgid "Allow allocation of substitute parts"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -1277,7 +1289,7 @@ msgstr ""
|
|||||||
#: order/templates/order/order_base.html:162
|
#: order/templates/order/order_base.html:162
|
||||||
#: order/templates/order/sales_order_base.html:164
|
#: order/templates/order/sales_order_base.html:164
|
||||||
#: report/templates/report/inventree_build_order_base.html:126
|
#: report/templates/report/inventree_build_order_base.html:126
|
||||||
#: templates/js/translated/build.js:2549 templates/js/translated/order.js:1677
|
#: templates/js/translated/build.js:2550 templates/js/translated/order.js:1677
|
||||||
#: templates/js/translated/order.js:1987 templates/js/translated/order.js:2497
|
#: templates/js/translated/order.js:1987 templates/js/translated/order.js:2497
|
||||||
#: templates/js/translated/order.js:3537 templates/js/translated/part.js:1040
|
#: templates/js/translated/order.js:3537 templates/js/translated/part.js:1040
|
||||||
msgid "Target Date"
|
msgid "Target Date"
|
||||||
@@ -1364,7 +1376,7 @@ msgstr ""
|
|||||||
|
|
||||||
#: build/templates/build/detail.html:80
|
#: build/templates/build/detail.html:80
|
||||||
#: stock/templates/stock/item_base.html:170
|
#: stock/templates/stock/item_base.html:170
|
||||||
#: templates/js/translated/build.js:1179
|
#: templates/js/translated/build.js:1180
|
||||||
#: templates/js/translated/model_renderers.js:124
|
#: templates/js/translated/model_renderers.js:124
|
||||||
#: templates/js/translated/stock.js:1022 templates/js/translated/stock.js:1839
|
#: templates/js/translated/stock.js:1022 templates/js/translated/stock.js:1839
|
||||||
#: templates/js/translated/stock.js:2669
|
#: templates/js/translated/stock.js:2669
|
||||||
@@ -1376,7 +1388,7 @@ msgstr ""
|
|||||||
#: build/templates/build/detail.html:126
|
#: build/templates/build/detail.html:126
|
||||||
#: order/templates/order/order_base.html:149
|
#: order/templates/order/order_base.html:149
|
||||||
#: order/templates/order/sales_order_base.html:158
|
#: order/templates/order/sales_order_base.html:158
|
||||||
#: templates/js/translated/build.js:2517
|
#: templates/js/translated/build.js:2518
|
||||||
msgid "Created"
|
msgid "Created"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -1396,7 +1408,7 @@ msgstr ""
|
|||||||
msgid "Allocate Stock to Build"
|
msgid "Allocate Stock to Build"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/templates/build/detail.html:176 templates/js/translated/build.js:1898
|
#: build/templates/build/detail.html:176 templates/js/translated/build.js:1899
|
||||||
msgid "Unallocate stock"
|
msgid "Unallocate stock"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -2868,8 +2880,8 @@ msgstr ""
|
|||||||
#: company/models.py:538 company/templates/company/supplier_part.html:94
|
#: company/models.py:538 company/templates/company/supplier_part.html:94
|
||||||
#: templates/email/build_order_required_stock.html:19
|
#: templates/email/build_order_required_stock.html:19
|
||||||
#: templates/email/low_stock_notification.html:18
|
#: templates/email/low_stock_notification.html:18
|
||||||
#: templates/js/translated/bom.js:884 templates/js/translated/build.js:1786
|
#: templates/js/translated/bom.js:884 templates/js/translated/build.js:1787
|
||||||
#: templates/js/translated/build.js:2649 templates/js/translated/company.js:959
|
#: templates/js/translated/build.js:2650 templates/js/translated/company.js:959
|
||||||
#: templates/js/translated/part.js:596 templates/js/translated/part.js:599
|
#: templates/js/translated/part.js:596 templates/js/translated/part.js:599
|
||||||
#: templates/js/translated/table_filters.js:178
|
#: templates/js/translated/table_filters.js:178
|
||||||
msgid "Available"
|
msgid "Available"
|
||||||
@@ -3063,7 +3075,7 @@ msgid "New Sales Order"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: company/templates/company/detail.html:168
|
#: company/templates/company/detail.html:168
|
||||||
#: templates/js/translated/build.js:1657
|
#: templates/js/translated/build.js:1658
|
||||||
msgid "Assigned Stock"
|
msgid "Assigned Stock"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -3985,8 +3997,8 @@ msgstr ""
|
|||||||
#: part/templates/part/import_wizard/ajax_match_fields.html:64
|
#: part/templates/part/import_wizard/ajax_match_fields.html:64
|
||||||
#: part/templates/part/import_wizard/ajax_match_references.html:42
|
#: part/templates/part/import_wizard/ajax_match_references.html:42
|
||||||
#: part/templates/part/import_wizard/match_references.html:49
|
#: part/templates/part/import_wizard/match_references.html:49
|
||||||
#: templates/js/translated/bom.js:77 templates/js/translated/build.js:427
|
#: templates/js/translated/bom.js:77 templates/js/translated/build.js:428
|
||||||
#: templates/js/translated/build.js:579 templates/js/translated/build.js:1971
|
#: templates/js/translated/build.js:580 templates/js/translated/build.js:1972
|
||||||
#: templates/js/translated/order.js:833 templates/js/translated/order.js:1265
|
#: templates/js/translated/order.js:833 templates/js/translated/order.js:1265
|
||||||
#: templates/js/translated/order.js:2742 templates/js/translated/stock.js:621
|
#: templates/js/translated/order.js:2742 templates/js/translated/stock.js:621
|
||||||
#: templates/js/translated/stock.js:789
|
#: templates/js/translated/stock.js:789
|
||||||
@@ -4109,7 +4121,7 @@ msgstr ""
|
|||||||
|
|
||||||
#: order/templates/order/sales_order_detail.html:72
|
#: order/templates/order/sales_order_detail.html:72
|
||||||
#: templates/attachment_table.html:6 templates/js/translated/bom.js:1047
|
#: templates/attachment_table.html:6 templates/js/translated/bom.js:1047
|
||||||
#: templates/js/translated/build.js:1879
|
#: templates/js/translated/build.js:1880
|
||||||
msgid "Actions"
|
msgid "Actions"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -4167,19 +4179,19 @@ msgstr ""
|
|||||||
msgid "This option must be selected"
|
msgid "This option must be selected"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: part/api.py:1073
|
#: part/api.py:1074
|
||||||
msgid "Must be greater than zero"
|
msgid "Must be greater than zero"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: part/api.py:1077
|
#: part/api.py:1078
|
||||||
msgid "Must be a valid quantity"
|
msgid "Must be a valid quantity"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: part/api.py:1092
|
#: part/api.py:1093
|
||||||
msgid "Specify location for initial part stock"
|
msgid "Specify location for initial part stock"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: part/api.py:1123 part/api.py:1127 part/api.py:1142 part/api.py:1146
|
#: part/api.py:1124 part/api.py:1128 part/api.py:1143 part/api.py:1147
|
||||||
msgid "This field is required"
|
msgid "This field is required"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -5773,8 +5785,8 @@ msgstr ""
|
|||||||
|
|
||||||
#: report/templates/report/inventree_test_report_base.html:79
|
#: report/templates/report/inventree_test_report_base.html:79
|
||||||
#: stock/models.py:641 stock/templates/stock/item_base.html:322
|
#: stock/models.py:641 stock/templates/stock/item_base.html:322
|
||||||
#: templates/js/translated/build.js:420 templates/js/translated/build.js:572
|
#: templates/js/translated/build.js:421 templates/js/translated/build.js:573
|
||||||
#: templates/js/translated/build.js:1173 templates/js/translated/build.js:1670
|
#: templates/js/translated/build.js:1174 templates/js/translated/build.js:1671
|
||||||
#: templates/js/translated/model_renderers.js:118
|
#: templates/js/translated/model_renderers.js:118
|
||||||
#: templates/js/translated/order.js:115 templates/js/translated/order.js:3240
|
#: templates/js/translated/order.js:115 templates/js/translated/order.js:3240
|
||||||
#: templates/js/translated/order.js:3329 templates/js/translated/stock.js:486
|
#: templates/js/translated/order.js:3329 templates/js/translated/stock.js:486
|
||||||
@@ -6395,7 +6407,7 @@ msgid "Available Quantity"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: stock/templates/stock/item_base.html:394
|
#: stock/templates/stock/item_base.html:394
|
||||||
#: templates/js/translated/build.js:1692
|
#: templates/js/translated/build.js:1693
|
||||||
msgid "No location set"
|
msgid "No location set"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -6808,7 +6820,7 @@ msgid "Plugin Settings"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/InvenTree/settings/plugin.html:16
|
#: templates/InvenTree/settings/plugin.html:16
|
||||||
msgid "Changing the settings below require you to immediatly restart the server. Do not change this while under active usage."
|
msgid "Changing the settings below require you to immediately restart the server. Do not change this while under active usage."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/InvenTree/settings/plugin.html:34
|
#: templates/InvenTree/settings/plugin.html:34
|
||||||
@@ -7689,19 +7701,19 @@ msgstr ""
|
|||||||
msgid "No attachments found"
|
msgid "No attachments found"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/attachment.js:218
|
#: templates/js/translated/attachment.js:219
|
||||||
msgid "Edit Attachment"
|
msgid "Edit Attachment"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/attachment.js:287
|
#: templates/js/translated/attachment.js:289
|
||||||
msgid "Upload Date"
|
msgid "Upload Date"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/attachment.js:310
|
#: templates/js/translated/attachment.js:312
|
||||||
msgid "Edit attachment"
|
msgid "Edit attachment"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/attachment.js:319
|
#: templates/js/translated/attachment.js:321
|
||||||
msgid "Delete attachment"
|
msgid "Delete attachment"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -7921,25 +7933,25 @@ msgstr ""
|
|||||||
msgid "Substitutes Available"
|
msgid "Substitutes Available"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/bom.js:832 templates/js/translated/build.js:1768
|
#: templates/js/translated/bom.js:832 templates/js/translated/build.js:1769
|
||||||
msgid "Variant stock allowed"
|
msgid "Variant stock allowed"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/bom.js:900 templates/js/translated/build.js:1813
|
#: templates/js/translated/bom.js:900 templates/js/translated/build.js:1814
|
||||||
#: templates/js/translated/order.js:3577
|
#: templates/js/translated/order.js:3577
|
||||||
msgid "No Stock Available"
|
msgid "No Stock Available"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/bom.js:904 templates/js/translated/build.js:1817
|
#: templates/js/translated/bom.js:904 templates/js/translated/build.js:1818
|
||||||
msgid "Includes variant and substitute stock"
|
msgid "Includes variant and substitute stock"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/bom.js:906 templates/js/translated/build.js:1819
|
#: templates/js/translated/bom.js:906 templates/js/translated/build.js:1820
|
||||||
#: templates/js/translated/part.js:759
|
#: templates/js/translated/part.js:759
|
||||||
msgid "Includes variant stock"
|
msgid "Includes variant stock"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/bom.js:908 templates/js/translated/build.js:1821
|
#: templates/js/translated/bom.js:908 templates/js/translated/build.js:1822
|
||||||
msgid "Includes substitute stock"
|
msgid "Includes substitute stock"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -7979,11 +7991,11 @@ msgstr ""
|
|||||||
msgid "Delete BOM Item"
|
msgid "Delete BOM Item"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/bom.js:1158 templates/js/translated/build.js:1614
|
#: templates/js/translated/bom.js:1158 templates/js/translated/build.js:1615
|
||||||
msgid "No BOM items found"
|
msgid "No BOM items found"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/bom.js:1402 templates/js/translated/build.js:1752
|
#: templates/js/translated/bom.js:1402 templates/js/translated/build.js:1753
|
||||||
msgid "Required Part"
|
msgid "Required Part"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -8015,256 +8027,256 @@ msgstr ""
|
|||||||
msgid "There are incomplete outputs remaining for this build order"
|
msgid "There are incomplete outputs remaining for this build order"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:185
|
#: templates/js/translated/build.js:186
|
||||||
msgid "Build order is ready to be completed"
|
msgid "Build order is ready to be completed"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:190
|
#: templates/js/translated/build.js:191
|
||||||
msgid "Build Order is incomplete"
|
msgid "Build Order is incomplete"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:218
|
#: templates/js/translated/build.js:219
|
||||||
msgid "Complete Build Order"
|
msgid "Complete Build Order"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:259 templates/js/translated/stock.js:92
|
#: templates/js/translated/build.js:260 templates/js/translated/stock.js:92
|
||||||
#: templates/js/translated/stock.js:210
|
#: templates/js/translated/stock.js:210
|
||||||
msgid "Next available serial number"
|
msgid "Next available serial number"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:261 templates/js/translated/stock.js:94
|
#: templates/js/translated/build.js:262 templates/js/translated/stock.js:94
|
||||||
#: templates/js/translated/stock.js:212
|
#: templates/js/translated/stock.js:212
|
||||||
msgid "Latest serial number"
|
msgid "Latest serial number"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:270
|
#: templates/js/translated/build.js:271
|
||||||
msgid "The Bill of Materials contains trackable parts"
|
msgid "The Bill of Materials contains trackable parts"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:271
|
#: templates/js/translated/build.js:272
|
||||||
msgid "Build outputs must be generated individually"
|
msgid "Build outputs must be generated individually"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:279
|
#: templates/js/translated/build.js:280
|
||||||
msgid "Trackable parts can have serial numbers specified"
|
msgid "Trackable parts can have serial numbers specified"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:280
|
#: templates/js/translated/build.js:281
|
||||||
msgid "Enter serial numbers to generate multiple single build outputs"
|
msgid "Enter serial numbers to generate multiple single build outputs"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:287
|
#: templates/js/translated/build.js:288
|
||||||
msgid "Create Build Output"
|
msgid "Create Build Output"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:318
|
#: templates/js/translated/build.js:319
|
||||||
msgid "Allocate stock items to this build output"
|
msgid "Allocate stock items to this build output"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:329
|
#: templates/js/translated/build.js:330
|
||||||
msgid "Unallocate stock from build output"
|
msgid "Unallocate stock from build output"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:338
|
#: templates/js/translated/build.js:339
|
||||||
msgid "Complete build output"
|
msgid "Complete build output"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:346
|
#: templates/js/translated/build.js:347
|
||||||
msgid "Delete build output"
|
msgid "Delete build output"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:369
|
#: templates/js/translated/build.js:370
|
||||||
msgid "Are you sure you wish to unallocate stock items from this build?"
|
msgid "Are you sure you wish to unallocate stock items from this build?"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:387
|
#: templates/js/translated/build.js:388
|
||||||
msgid "Unallocate Stock Items"
|
msgid "Unallocate Stock Items"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:407 templates/js/translated/build.js:559
|
#: templates/js/translated/build.js:408 templates/js/translated/build.js:560
|
||||||
msgid "Select Build Outputs"
|
msgid "Select Build Outputs"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:408 templates/js/translated/build.js:560
|
#: templates/js/translated/build.js:409 templates/js/translated/build.js:561
|
||||||
msgid "At least one build output must be selected"
|
msgid "At least one build output must be selected"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:462 templates/js/translated/build.js:614
|
#: templates/js/translated/build.js:463 templates/js/translated/build.js:615
|
||||||
msgid "Output"
|
msgid "Output"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:480
|
#: templates/js/translated/build.js:481
|
||||||
msgid "Complete Build Outputs"
|
msgid "Complete Build Outputs"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:627
|
#: templates/js/translated/build.js:628
|
||||||
msgid "Delete Build Outputs"
|
msgid "Delete Build Outputs"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:716
|
#: templates/js/translated/build.js:717
|
||||||
msgid "No build order allocations found"
|
msgid "No build order allocations found"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:754
|
#: templates/js/translated/build.js:755
|
||||||
msgid "Location not specified"
|
msgid "Location not specified"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:1133
|
#: templates/js/translated/build.js:1134
|
||||||
msgid "No active build outputs found"
|
msgid "No active build outputs found"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:1202
|
#: templates/js/translated/build.js:1203
|
||||||
msgid "Allocated Stock"
|
msgid "Allocated Stock"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:1209
|
#: templates/js/translated/build.js:1210
|
||||||
msgid "No tracked BOM items for this build"
|
msgid "No tracked BOM items for this build"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:1231
|
#: templates/js/translated/build.js:1232
|
||||||
msgid "Completed Tests"
|
msgid "Completed Tests"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:1236
|
#: templates/js/translated/build.js:1237
|
||||||
msgid "No required tests for this build"
|
msgid "No required tests for this build"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:1709 templates/js/translated/build.js:2660
|
#: templates/js/translated/build.js:1710 templates/js/translated/build.js:2661
|
||||||
#: templates/js/translated/order.js:3277
|
#: templates/js/translated/order.js:3277
|
||||||
msgid "Edit stock allocation"
|
msgid "Edit stock allocation"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:1711 templates/js/translated/build.js:2661
|
#: templates/js/translated/build.js:1712 templates/js/translated/build.js:2662
|
||||||
#: templates/js/translated/order.js:3278
|
#: templates/js/translated/order.js:3278
|
||||||
msgid "Delete stock allocation"
|
msgid "Delete stock allocation"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:1729
|
#: templates/js/translated/build.js:1730
|
||||||
msgid "Edit Allocation"
|
msgid "Edit Allocation"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:1739
|
#: templates/js/translated/build.js:1740
|
||||||
msgid "Remove Allocation"
|
msgid "Remove Allocation"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:1764
|
#: templates/js/translated/build.js:1765
|
||||||
msgid "Substitute parts available"
|
msgid "Substitute parts available"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:1781
|
#: templates/js/translated/build.js:1782
|
||||||
msgid "Quantity Per"
|
msgid "Quantity Per"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:1807 templates/js/translated/order.js:3584
|
#: templates/js/translated/build.js:1808 templates/js/translated/order.js:3584
|
||||||
msgid "Insufficient stock available"
|
msgid "Insufficient stock available"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:1809 templates/js/translated/order.js:3582
|
#: templates/js/translated/build.js:1810 templates/js/translated/order.js:3582
|
||||||
msgid "Sufficient stock available"
|
msgid "Sufficient stock available"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:1838 templates/js/translated/build.js:2083
|
#: templates/js/translated/build.js:1839 templates/js/translated/build.js:2084
|
||||||
#: templates/js/translated/build.js:2656 templates/js/translated/order.js:3596
|
#: templates/js/translated/build.js:2657 templates/js/translated/order.js:3596
|
||||||
msgid "Allocated"
|
msgid "Allocated"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:1886 templates/js/translated/order.js:3676
|
#: templates/js/translated/build.js:1887 templates/js/translated/order.js:3676
|
||||||
msgid "Build stock"
|
msgid "Build stock"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:1890 templates/stock_table.html:50
|
#: templates/js/translated/build.js:1891 templates/stock_table.html:50
|
||||||
msgid "Order stock"
|
msgid "Order stock"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:1893 templates/js/translated/order.js:3669
|
#: templates/js/translated/build.js:1894 templates/js/translated/order.js:3669
|
||||||
msgid "Allocate stock"
|
msgid "Allocate stock"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:1932 templates/js/translated/label.js:172
|
#: templates/js/translated/build.js:1933 templates/js/translated/label.js:172
|
||||||
#: templates/js/translated/order.js:756 templates/js/translated/order.js:2804
|
#: templates/js/translated/order.js:756 templates/js/translated/order.js:2804
|
||||||
#: templates/js/translated/report.js:225
|
#: templates/js/translated/report.js:225
|
||||||
msgid "Select Parts"
|
msgid "Select Parts"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:1933 templates/js/translated/order.js:2805
|
#: templates/js/translated/build.js:1934 templates/js/translated/order.js:2805
|
||||||
msgid "You must select at least one part to allocate"
|
msgid "You must select at least one part to allocate"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:1982 templates/js/translated/order.js:2753
|
#: templates/js/translated/build.js:1983 templates/js/translated/order.js:2753
|
||||||
msgid "Specify stock allocation quantity"
|
msgid "Specify stock allocation quantity"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:2056
|
#: templates/js/translated/build.js:2057
|
||||||
msgid "All Parts Allocated"
|
msgid "All Parts Allocated"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:2057
|
#: templates/js/translated/build.js:2058
|
||||||
msgid "All selected parts have been fully allocated"
|
msgid "All selected parts have been fully allocated"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:2071 templates/js/translated/order.js:2819
|
#: templates/js/translated/build.js:2072 templates/js/translated/order.js:2819
|
||||||
msgid "Select source location (leave blank to take from all locations)"
|
msgid "Select source location (leave blank to take from all locations)"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:2099
|
#: templates/js/translated/build.js:2100
|
||||||
msgid "Allocate Stock Items to Build Order"
|
msgid "Allocate Stock Items to Build Order"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:2110 templates/js/translated/order.js:2916
|
#: templates/js/translated/build.js:2111 templates/js/translated/order.js:2916
|
||||||
msgid "No matching stock locations"
|
msgid "No matching stock locations"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:2182 templates/js/translated/order.js:2993
|
#: templates/js/translated/build.js:2183 templates/js/translated/order.js:2993
|
||||||
msgid "No matching stock items"
|
msgid "No matching stock items"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:2279
|
#: templates/js/translated/build.js:2280
|
||||||
msgid "Automatic Stock Allocation"
|
msgid "Automatic Stock Allocation"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:2280
|
#: templates/js/translated/build.js:2281
|
||||||
msgid "Stock items will be automatically allocated to this build order, according to the provided guidelines"
|
msgid "Stock items will be automatically allocated to this build order, according to the provided guidelines"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:2282
|
#: templates/js/translated/build.js:2283
|
||||||
msgid "If a location is specifed, stock will only be allocated from that location"
|
msgid "If a location is specifed, stock will only be allocated from that location"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:2283
|
#: templates/js/translated/build.js:2284
|
||||||
msgid "If stock is considered interchangeable, it will be allocated from the first location it is found"
|
msgid "If stock is considered interchangeable, it will be allocated from the first location it is found"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:2284
|
#: templates/js/translated/build.js:2285
|
||||||
msgid "If substitute stock is allowed, it will be used where stock of the primary part cannot be found"
|
msgid "If substitute stock is allowed, it will be used where stock of the primary part cannot be found"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:2305
|
#: templates/js/translated/build.js:2306
|
||||||
msgid "Allocate Stock Items"
|
msgid "Allocate Stock Items"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:2412
|
#: templates/js/translated/build.js:2413
|
||||||
msgid "No builds matching query"
|
msgid "No builds matching query"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:2447 templates/js/translated/part.js:1383
|
#: templates/js/translated/build.js:2448 templates/js/translated/part.js:1383
|
||||||
#: templates/js/translated/part.js:1850 templates/js/translated/stock.js:1682
|
#: templates/js/translated/part.js:1850 templates/js/translated/stock.js:1682
|
||||||
#: templates/js/translated/stock.js:2340
|
#: templates/js/translated/stock.js:2340
|
||||||
msgid "Select"
|
msgid "Select"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:2467
|
#: templates/js/translated/build.js:2468
|
||||||
msgid "Build order is overdue"
|
msgid "Build order is overdue"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:2495
|
#: templates/js/translated/build.js:2496
|
||||||
msgid "Progress"
|
msgid "Progress"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:2531 templates/js/translated/stock.js:2582
|
#: templates/js/translated/build.js:2532 templates/js/translated/stock.js:2582
|
||||||
msgid "No user information"
|
msgid "No user information"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:2637
|
#: templates/js/translated/build.js:2638
|
||||||
msgid "No parts allocated for"
|
msgid "No parts allocated for"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -10058,61 +10070,61 @@ msgstr ""
|
|||||||
msgid "Select File Format"
|
msgid "Select File Format"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/tables.js:534
|
#: templates/js/translated/tables.js:535
|
||||||
msgid "Loading data"
|
msgid "Loading data"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/tables.js:537
|
#: templates/js/translated/tables.js:538
|
||||||
msgid "rows per page"
|
msgid "rows per page"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/tables.js:542
|
#: templates/js/translated/tables.js:543
|
||||||
msgid "Showing all rows"
|
msgid "Showing all rows"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/tables.js:544
|
#: templates/js/translated/tables.js:545
|
||||||
msgid "Showing"
|
msgid "Showing"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/tables.js:544
|
#: templates/js/translated/tables.js:545
|
||||||
msgid "to"
|
msgid "to"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/tables.js:544
|
#: templates/js/translated/tables.js:545
|
||||||
msgid "of"
|
msgid "of"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/tables.js:544
|
#: templates/js/translated/tables.js:545
|
||||||
msgid "rows"
|
msgid "rows"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/tables.js:548 templates/navbar.html:102
|
#: templates/js/translated/tables.js:549 templates/navbar.html:102
|
||||||
#: templates/search.html:8 templates/search_form.html:6
|
#: templates/search.html:8 templates/search_form.html:6
|
||||||
#: templates/search_form.html:7
|
#: templates/search_form.html:7
|
||||||
msgid "Search"
|
msgid "Search"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/tables.js:551
|
#: templates/js/translated/tables.js:552
|
||||||
msgid "No matching results"
|
msgid "No matching results"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/tables.js:554
|
#: templates/js/translated/tables.js:555
|
||||||
msgid "Hide/Show pagination"
|
msgid "Hide/Show pagination"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/tables.js:557
|
#: templates/js/translated/tables.js:558
|
||||||
msgid "Refresh"
|
msgid "Refresh"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/tables.js:560
|
#: templates/js/translated/tables.js:561
|
||||||
msgid "Toggle"
|
msgid "Toggle"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/tables.js:563
|
#: templates/js/translated/tables.js:564
|
||||||
msgid "Columns"
|
msgid "Columns"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/tables.js:566
|
#: templates/js/translated/tables.js:567
|
||||||
msgid "All"
|
msgid "All"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|||||||
+2317
-2310
File diff suppressed because it is too large
Load Diff
@@ -8,7 +8,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2022-06-28 12:13+0000\n"
|
"POT-Creation-Date: 2022-07-04 02:07+0000\n"
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
@@ -141,7 +141,7 @@ msgstr ""
|
|||||||
|
|
||||||
#: InvenTree/models.py:191 stock/models.py:2096
|
#: InvenTree/models.py:191 stock/models.py:2096
|
||||||
#: templates/js/translated/attachment.js:103
|
#: templates/js/translated/attachment.js:103
|
||||||
#: templates/js/translated/attachment.js:239
|
#: templates/js/translated/attachment.js:240
|
||||||
msgid "Attachment"
|
msgid "Attachment"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -165,7 +165,7 @@ msgid "Link to external URL"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: InvenTree/models.py:202 templates/js/translated/attachment.js:104
|
#: InvenTree/models.py:202 templates/js/translated/attachment.js:104
|
||||||
#: templates/js/translated/attachment.js:283
|
#: templates/js/translated/attachment.js:284
|
||||||
msgid "Comment"
|
msgid "Comment"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -243,7 +243,7 @@ msgstr ""
|
|||||||
#: stock/templates/stock/location.html:103
|
#: stock/templates/stock/location.html:103
|
||||||
#: templates/InvenTree/settings/plugin_settings.html:33
|
#: templates/InvenTree/settings/plugin_settings.html:33
|
||||||
#: templates/js/translated/bom.js:553 templates/js/translated/bom.js:845
|
#: templates/js/translated/bom.js:553 templates/js/translated/bom.js:845
|
||||||
#: templates/js/translated/build.js:2475 templates/js/translated/company.js:397
|
#: templates/js/translated/build.js:2476 templates/js/translated/company.js:397
|
||||||
#: templates/js/translated/company.js:653
|
#: templates/js/translated/company.js:653
|
||||||
#: templates/js/translated/company.js:944 templates/js/translated/order.js:1656
|
#: templates/js/translated/company.js:944 templates/js/translated/order.js:1656
|
||||||
#: templates/js/translated/order.js:1888 templates/js/translated/order.js:2476
|
#: templates/js/translated/order.js:1888 templates/js/translated/order.js:2476
|
||||||
@@ -656,7 +656,7 @@ msgstr ""
|
|||||||
#: report/templates/report/inventree_build_order_base.html:106
|
#: report/templates/report/inventree_build_order_base.html:106
|
||||||
#: templates/email/build_order_completed.html:16
|
#: templates/email/build_order_completed.html:16
|
||||||
#: templates/email/overdue_build_order.html:15
|
#: templates/email/overdue_build_order.html:15
|
||||||
#: templates/js/translated/build.js:727
|
#: templates/js/translated/build.js:728
|
||||||
msgid "Build Order"
|
msgid "Build Order"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -680,7 +680,7 @@ msgstr ""
|
|||||||
#: report/templates/report/inventree_po_report.html:91
|
#: report/templates/report/inventree_po_report.html:91
|
||||||
#: report/templates/report/inventree_so_report.html:92
|
#: report/templates/report/inventree_so_report.html:92
|
||||||
#: templates/js/translated/bom.js:690 templates/js/translated/bom.js:852
|
#: templates/js/translated/bom.js:690 templates/js/translated/bom.js:852
|
||||||
#: templates/js/translated/build.js:1776 templates/js/translated/order.js:1919
|
#: templates/js/translated/build.js:1777 templates/js/translated/order.js:1919
|
||||||
#: templates/js/translated/order.js:2120 templates/js/translated/order.js:3468
|
#: templates/js/translated/order.js:2120 templates/js/translated/order.js:3468
|
||||||
#: templates/js/translated/order.js:3976
|
#: templates/js/translated/order.js:3976
|
||||||
msgid "Reference"
|
msgid "Reference"
|
||||||
@@ -719,8 +719,8 @@ msgstr ""
|
|||||||
#: templates/email/overdue_build_order.html:16
|
#: templates/email/overdue_build_order.html:16
|
||||||
#: templates/js/translated/barcode.js:435 templates/js/translated/bom.js:552
|
#: templates/js/translated/barcode.js:435 templates/js/translated/bom.js:552
|
||||||
#: templates/js/translated/bom.js:689 templates/js/translated/bom.js:799
|
#: templates/js/translated/bom.js:689 templates/js/translated/bom.js:799
|
||||||
#: templates/js/translated/build.js:1153 templates/js/translated/build.js:1646
|
#: templates/js/translated/build.js:1154 templates/js/translated/build.js:1647
|
||||||
#: templates/js/translated/build.js:2082 templates/js/translated/build.js:2480
|
#: templates/js/translated/build.js:2083 templates/js/translated/build.js:2481
|
||||||
#: templates/js/translated/company.js:255
|
#: templates/js/translated/company.js:255
|
||||||
#: templates/js/translated/company.js:484
|
#: templates/js/translated/company.js:484
|
||||||
#: templates/js/translated/company.js:594
|
#: templates/js/translated/company.js:594
|
||||||
@@ -748,8 +748,8 @@ msgstr ""
|
|||||||
msgid "SalesOrder to which this build is allocated"
|
msgid "SalesOrder to which this build is allocated"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/models.py:236 build/serializers.py:758
|
#: build/models.py:236 build/serializers.py:774
|
||||||
#: templates/js/translated/build.js:2070 templates/js/translated/order.js:2818
|
#: templates/js/translated/build.js:2071 templates/js/translated/order.js:2818
|
||||||
msgid "Source Location"
|
msgid "Source Location"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -812,7 +812,7 @@ msgid "Target date for build completion. Build will be overdue after this date."
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/models.py:289 order/models.py:323
|
#: build/models.py:289 order/models.py:323
|
||||||
#: templates/js/translated/build.js:2557
|
#: templates/js/translated/build.js:2558
|
||||||
msgid "Completion Date"
|
msgid "Completion Date"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -820,7 +820,7 @@ msgstr ""
|
|||||||
msgid "completed by"
|
msgid "completed by"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/models.py:303 templates/js/translated/build.js:2525
|
#: build/models.py:303 templates/js/translated/build.js:2526
|
||||||
msgid "Issued by"
|
msgid "Issued by"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -833,7 +833,7 @@ msgstr ""
|
|||||||
#: order/templates/order/order_base.html:176
|
#: order/templates/order/order_base.html:176
|
||||||
#: order/templates/order/sales_order_base.html:183 part/models.py:935
|
#: order/templates/order/sales_order_base.html:183 part/models.py:935
|
||||||
#: report/templates/report/inventree_build_order_base.html:159
|
#: report/templates/report/inventree_build_order_base.html:159
|
||||||
#: templates/js/translated/build.js:2537 templates/js/translated/order.js:1690
|
#: templates/js/translated/build.js:2538 templates/js/translated/order.js:1690
|
||||||
msgid "Responsible"
|
msgid "Responsible"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -874,48 +874,48 @@ msgstr ""
|
|||||||
msgid "Build output does not match Build Order"
|
msgid "Build output does not match Build Order"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/models.py:1148
|
#: build/models.py:1162
|
||||||
msgid "Build item must specify a build output, as master part is marked as trackable"
|
msgid "Build item must specify a build output, as master part is marked as trackable"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/models.py:1157
|
#: build/models.py:1171
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Allocated quantity ({q}) must not exceed available stock quantity ({a})"
|
msgid "Allocated quantity ({q}) must not exceed available stock quantity ({a})"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/models.py:1167
|
#: build/models.py:1181
|
||||||
msgid "Stock item is over-allocated"
|
msgid "Stock item is over-allocated"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/models.py:1173 order/models.py:1404
|
#: build/models.py:1187 order/models.py:1404
|
||||||
msgid "Allocation quantity must be greater than zero"
|
msgid "Allocation quantity must be greater than zero"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/models.py:1179
|
#: build/models.py:1193
|
||||||
msgid "Quantity must be 1 for serialized stock"
|
msgid "Quantity must be 1 for serialized stock"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/models.py:1236
|
#: build/models.py:1250
|
||||||
msgid "Selected stock item not found in BOM"
|
msgid "Selected stock item not found in BOM"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/models.py:1305 stock/templates/stock/item_base.html:177
|
#: build/models.py:1319 stock/templates/stock/item_base.html:177
|
||||||
#: templates/InvenTree/search.html:137 templates/js/translated/build.js:2453
|
#: templates/InvenTree/search.html:137 templates/js/translated/build.js:2454
|
||||||
#: templates/navbar.html:38
|
#: templates/navbar.html:38
|
||||||
msgid "Build"
|
msgid "Build"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/models.py:1306
|
#: build/models.py:1320
|
||||||
msgid "Build to allocate parts"
|
msgid "Build to allocate parts"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/models.py:1322 build/serializers.py:603 order/serializers.py:996
|
#: build/models.py:1336 build/serializers.py:619 order/serializers.py:996
|
||||||
#: order/serializers.py:1017 stock/serializers.py:394 stock/serializers.py:741
|
#: order/serializers.py:1017 stock/serializers.py:394 stock/serializers.py:741
|
||||||
#: stock/serializers.py:867 stock/templates/stock/item_base.html:10
|
#: stock/serializers.py:867 stock/templates/stock/item_base.html:10
|
||||||
#: stock/templates/stock/item_base.html:23
|
#: stock/templates/stock/item_base.html:23
|
||||||
#: stock/templates/stock/item_base.html:199
|
#: stock/templates/stock/item_base.html:199
|
||||||
#: templates/js/translated/build.js:738 templates/js/translated/build.js:743
|
#: templates/js/translated/build.js:739 templates/js/translated/build.js:744
|
||||||
#: templates/js/translated/build.js:2084 templates/js/translated/build.js:2642
|
#: templates/js/translated/build.js:2085 templates/js/translated/build.js:2643
|
||||||
#: templates/js/translated/order.js:101 templates/js/translated/order.js:2831
|
#: templates/js/translated/order.js:101 templates/js/translated/order.js:2831
|
||||||
#: templates/js/translated/order.js:3135 templates/js/translated/order.js:3140
|
#: templates/js/translated/order.js:3135 templates/js/translated/order.js:3140
|
||||||
#: templates/js/translated/order.js:3235 templates/js/translated/order.js:3325
|
#: templates/js/translated/order.js:3235 templates/js/translated/order.js:3325
|
||||||
@@ -924,11 +924,11 @@ msgstr ""
|
|||||||
msgid "Stock Item"
|
msgid "Stock Item"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/models.py:1323
|
#: build/models.py:1337
|
||||||
msgid "Source stock item"
|
msgid "Source stock item"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/models.py:1335 build/serializers.py:183
|
#: build/models.py:1349 build/serializers.py:183
|
||||||
#: build/templates/build/build_base.html:82
|
#: build/templates/build/build_base.html:82
|
||||||
#: build/templates/build/detail.html:34 common/models.py:1644
|
#: build/templates/build/detail.html:34 common/models.py:1644
|
||||||
#: company/forms.py:36 company/templates/company/supplier_part.html:279
|
#: company/forms.py:36 company/templates/company/supplier_part.html:279
|
||||||
@@ -947,10 +947,10 @@ msgstr ""
|
|||||||
#: stock/templates/stock/item_base.html:300
|
#: stock/templates/stock/item_base.html:300
|
||||||
#: templates/email/build_order_completed.html:18
|
#: templates/email/build_order_completed.html:18
|
||||||
#: templates/js/translated/barcode.js:437 templates/js/translated/bom.js:691
|
#: templates/js/translated/barcode.js:437 templates/js/translated/bom.js:691
|
||||||
#: templates/js/translated/bom.js:860 templates/js/translated/build.js:422
|
#: templates/js/translated/bom.js:860 templates/js/translated/build.js:423
|
||||||
#: templates/js/translated/build.js:574 templates/js/translated/build.js:765
|
#: templates/js/translated/build.js:575 templates/js/translated/build.js:766
|
||||||
#: templates/js/translated/build.js:1175 templates/js/translated/build.js:1672
|
#: templates/js/translated/build.js:1176 templates/js/translated/build.js:1673
|
||||||
#: templates/js/translated/build.js:2085
|
#: templates/js/translated/build.js:2086
|
||||||
#: templates/js/translated/model_renderers.js:120
|
#: templates/js/translated/model_renderers.js:120
|
||||||
#: templates/js/translated/order.js:117 templates/js/translated/order.js:886
|
#: templates/js/translated/order.js:117 templates/js/translated/order.js:886
|
||||||
#: templates/js/translated/order.js:1925 templates/js/translated/order.js:2126
|
#: templates/js/translated/order.js:1925 templates/js/translated/order.js:2126
|
||||||
@@ -965,20 +965,20 @@ msgstr ""
|
|||||||
msgid "Quantity"
|
msgid "Quantity"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/models.py:1336
|
#: build/models.py:1350
|
||||||
msgid "Stock quantity to allocate to build"
|
msgid "Stock quantity to allocate to build"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/models.py:1344
|
#: build/models.py:1358
|
||||||
msgid "Install into"
|
msgid "Install into"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/models.py:1345
|
#: build/models.py:1359
|
||||||
msgid "Destination stock item"
|
msgid "Destination stock item"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/serializers.py:128 build/serializers.py:632
|
#: build/serializers.py:128 build/serializers.py:648
|
||||||
#: templates/js/translated/build.js:1163
|
#: templates/js/translated/build.js:1164
|
||||||
msgid "Build Output"
|
msgid "Build Output"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -1002,7 +1002,7 @@ msgstr ""
|
|||||||
msgid "Enter quantity for build output"
|
msgid "Enter quantity for build output"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/serializers.py:198 build/serializers.py:623 order/models.py:355
|
#: build/serializers.py:198 build/serializers.py:639 order/models.py:355
|
||||||
#: order/serializers.py:280 order/serializers.py:435 part/serializers.py:503
|
#: order/serializers.py:280 order/serializers.py:435 part/serializers.py:503
|
||||||
#: part/serializers.py:926 stock/models.py:478 stock/models.py:1244
|
#: part/serializers.py:926 stock/models.py:478 stock/models.py:1244
|
||||||
#: stock/serializers.py:300
|
#: stock/serializers.py:300
|
||||||
@@ -1048,8 +1048,8 @@ msgstr ""
|
|||||||
#: stock/serializers.py:902 stock/serializers.py:1135
|
#: stock/serializers.py:902 stock/serializers.py:1135
|
||||||
#: stock/templates/stock/item_base.html:390
|
#: stock/templates/stock/item_base.html:390
|
||||||
#: templates/js/translated/barcode.js:436
|
#: templates/js/translated/barcode.js:436
|
||||||
#: templates/js/translated/barcode.js:618 templates/js/translated/build.js:750
|
#: templates/js/translated/barcode.js:618 templates/js/translated/build.js:751
|
||||||
#: templates/js/translated/build.js:1684 templates/js/translated/order.js:1213
|
#: templates/js/translated/build.js:1685 templates/js/translated/order.js:1213
|
||||||
#: templates/js/translated/order.js:3147 templates/js/translated/order.js:3250
|
#: templates/js/translated/order.js:3147 templates/js/translated/order.js:3250
|
||||||
#: templates/js/translated/order.js:3258 templates/js/translated/order.js:3339
|
#: templates/js/translated/order.js:3258 templates/js/translated/order.js:3339
|
||||||
#: templates/js/translated/part.js:181 templates/js/translated/stock.js:584
|
#: templates/js/translated/part.js:181 templates/js/translated/stock.js:584
|
||||||
@@ -1065,7 +1065,7 @@ msgstr ""
|
|||||||
#: build/serializers.py:363 build/templates/build/build_base.html:142
|
#: build/serializers.py:363 build/templates/build/build_base.html:142
|
||||||
#: build/templates/build/detail.html:62 order/models.py:665
|
#: build/templates/build/detail.html:62 order/models.py:665
|
||||||
#: order/serializers.py:458 stock/templates/stock/item_base.html:423
|
#: order/serializers.py:458 stock/templates/stock/item_base.html:423
|
||||||
#: templates/js/translated/barcode.js:182 templates/js/translated/build.js:2509
|
#: templates/js/translated/barcode.js:182 templates/js/translated/build.js:2510
|
||||||
#: templates/js/translated/order.js:1320 templates/js/translated/order.js:1660
|
#: templates/js/translated/order.js:1320 templates/js/translated/order.js:1660
|
||||||
#: templates/js/translated/order.js:2481 templates/js/translated/stock.js:1825
|
#: templates/js/translated/order.js:2481 templates/js/translated/stock.js:1825
|
||||||
#: templates/js/translated/stock.js:2530 templates/js/translated/stock.js:2662
|
#: templates/js/translated/stock.js:2530 templates/js/translated/stock.js:2662
|
||||||
@@ -1097,104 +1097,116 @@ msgid "Delete any build outputs which have not been completed"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/serializers.py:470
|
#: build/serializers.py:470
|
||||||
msgid "Accept Unallocated"
|
msgid "Accept Overallocated"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/serializers.py:471
|
#: build/serializers.py:471
|
||||||
msgid "Accept that stock items have not been fully allocated to this build order"
|
msgid "Accept stock items which have been overallocated to this build order"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/serializers.py:481 templates/js/translated/build.js:195
|
#: build/serializers.py:481
|
||||||
msgid "Required stock has not been fully allocated"
|
msgid "Some stock items have been overallocated"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/serializers.py:486
|
#: build/serializers.py:486
|
||||||
msgid "Accept Incomplete"
|
msgid "Accept Unallocated"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/serializers.py:487
|
#: build/serializers.py:487
|
||||||
|
msgid "Accept that stock items have not been fully allocated to this build order"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: build/serializers.py:497 templates/js/translated/build.js:196
|
||||||
|
msgid "Required stock has not been fully allocated"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: build/serializers.py:502
|
||||||
|
msgid "Accept Incomplete"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: build/serializers.py:503
|
||||||
msgid "Accept that the required number of build outputs have not been completed"
|
msgid "Accept that the required number of build outputs have not been completed"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/serializers.py:497 templates/js/translated/build.js:199
|
#: build/serializers.py:513 templates/js/translated/build.js:200
|
||||||
msgid "Required build quantity has not been completed"
|
msgid "Required build quantity has not been completed"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/serializers.py:506
|
#: build/serializers.py:522
|
||||||
msgid "Build order has incomplete outputs"
|
msgid "Build order has incomplete outputs"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/serializers.py:509 build/templates/build/build_base.html:95
|
#: build/serializers.py:525 build/templates/build/build_base.html:95
|
||||||
msgid "No build outputs have been created for this build order"
|
msgid "No build outputs have been created for this build order"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/serializers.py:535 build/serializers.py:580 part/models.py:2719
|
#: build/serializers.py:551 build/serializers.py:596 part/models.py:2719
|
||||||
#: part/models.py:2853
|
#: part/models.py:2853
|
||||||
msgid "BOM Item"
|
msgid "BOM Item"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/serializers.py:545
|
#: build/serializers.py:561
|
||||||
msgid "Build output"
|
msgid "Build output"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/serializers.py:553
|
#: build/serializers.py:569
|
||||||
msgid "Build output must point to the same build"
|
msgid "Build output must point to the same build"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/serializers.py:594
|
#: build/serializers.py:610
|
||||||
msgid "bom_item.part must point to the same part as the build order"
|
msgid "bom_item.part must point to the same part as the build order"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/serializers.py:609 stock/serializers.py:754
|
#: build/serializers.py:625 stock/serializers.py:754
|
||||||
msgid "Item must be in stock"
|
msgid "Item must be in stock"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/serializers.py:667 order/serializers.py:1054
|
#: build/serializers.py:683 order/serializers.py:1054
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Available quantity ({q}) exceeded"
|
msgid "Available quantity ({q}) exceeded"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/serializers.py:673
|
#: build/serializers.py:689
|
||||||
msgid "Build output must be specified for allocation of tracked parts"
|
msgid "Build output must be specified for allocation of tracked parts"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/serializers.py:680
|
#: build/serializers.py:696
|
||||||
msgid "Build output cannot be specified for allocation of untracked parts"
|
msgid "Build output cannot be specified for allocation of untracked parts"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/serializers.py:685
|
#: build/serializers.py:701
|
||||||
msgid "This stock item has already been allocated to this build output"
|
msgid "This stock item has already been allocated to this build output"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/serializers.py:708 order/serializers.py:1300
|
#: build/serializers.py:724 order/serializers.py:1300
|
||||||
msgid "Allocation items must be provided"
|
msgid "Allocation items must be provided"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/serializers.py:759
|
#: build/serializers.py:775
|
||||||
msgid "Stock location where parts are to be sourced (leave blank to take from any location)"
|
msgid "Stock location where parts are to be sourced (leave blank to take from any location)"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/serializers.py:767
|
#: build/serializers.py:783
|
||||||
msgid "Exclude Location"
|
msgid "Exclude Location"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/serializers.py:768
|
#: build/serializers.py:784
|
||||||
msgid "Exclude stock items from this selected location"
|
msgid "Exclude stock items from this selected location"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/serializers.py:773
|
#: build/serializers.py:789
|
||||||
msgid "Interchangeable Stock"
|
msgid "Interchangeable Stock"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/serializers.py:774
|
#: build/serializers.py:790
|
||||||
msgid "Stock items in multiple locations can be used interchangeably"
|
msgid "Stock items in multiple locations can be used interchangeably"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/serializers.py:779
|
#: build/serializers.py:795
|
||||||
msgid "Substitute Stock"
|
msgid "Substitute Stock"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/serializers.py:780
|
#: build/serializers.py:796
|
||||||
msgid "Allow allocation of substitute parts"
|
msgid "Allow allocation of substitute parts"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -1277,7 +1289,7 @@ msgstr ""
|
|||||||
#: order/templates/order/order_base.html:162
|
#: order/templates/order/order_base.html:162
|
||||||
#: order/templates/order/sales_order_base.html:164
|
#: order/templates/order/sales_order_base.html:164
|
||||||
#: report/templates/report/inventree_build_order_base.html:126
|
#: report/templates/report/inventree_build_order_base.html:126
|
||||||
#: templates/js/translated/build.js:2549 templates/js/translated/order.js:1677
|
#: templates/js/translated/build.js:2550 templates/js/translated/order.js:1677
|
||||||
#: templates/js/translated/order.js:1987 templates/js/translated/order.js:2497
|
#: templates/js/translated/order.js:1987 templates/js/translated/order.js:2497
|
||||||
#: templates/js/translated/order.js:3537 templates/js/translated/part.js:1040
|
#: templates/js/translated/order.js:3537 templates/js/translated/part.js:1040
|
||||||
msgid "Target Date"
|
msgid "Target Date"
|
||||||
@@ -1364,7 +1376,7 @@ msgstr ""
|
|||||||
|
|
||||||
#: build/templates/build/detail.html:80
|
#: build/templates/build/detail.html:80
|
||||||
#: stock/templates/stock/item_base.html:170
|
#: stock/templates/stock/item_base.html:170
|
||||||
#: templates/js/translated/build.js:1179
|
#: templates/js/translated/build.js:1180
|
||||||
#: templates/js/translated/model_renderers.js:124
|
#: templates/js/translated/model_renderers.js:124
|
||||||
#: templates/js/translated/stock.js:1022 templates/js/translated/stock.js:1839
|
#: templates/js/translated/stock.js:1022 templates/js/translated/stock.js:1839
|
||||||
#: templates/js/translated/stock.js:2669
|
#: templates/js/translated/stock.js:2669
|
||||||
@@ -1376,7 +1388,7 @@ msgstr ""
|
|||||||
#: build/templates/build/detail.html:126
|
#: build/templates/build/detail.html:126
|
||||||
#: order/templates/order/order_base.html:149
|
#: order/templates/order/order_base.html:149
|
||||||
#: order/templates/order/sales_order_base.html:158
|
#: order/templates/order/sales_order_base.html:158
|
||||||
#: templates/js/translated/build.js:2517
|
#: templates/js/translated/build.js:2518
|
||||||
msgid "Created"
|
msgid "Created"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -1396,7 +1408,7 @@ msgstr ""
|
|||||||
msgid "Allocate Stock to Build"
|
msgid "Allocate Stock to Build"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/templates/build/detail.html:176 templates/js/translated/build.js:1898
|
#: build/templates/build/detail.html:176 templates/js/translated/build.js:1899
|
||||||
msgid "Unallocate stock"
|
msgid "Unallocate stock"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -2868,8 +2880,8 @@ msgstr ""
|
|||||||
#: company/models.py:538 company/templates/company/supplier_part.html:94
|
#: company/models.py:538 company/templates/company/supplier_part.html:94
|
||||||
#: templates/email/build_order_required_stock.html:19
|
#: templates/email/build_order_required_stock.html:19
|
||||||
#: templates/email/low_stock_notification.html:18
|
#: templates/email/low_stock_notification.html:18
|
||||||
#: templates/js/translated/bom.js:884 templates/js/translated/build.js:1786
|
#: templates/js/translated/bom.js:884 templates/js/translated/build.js:1787
|
||||||
#: templates/js/translated/build.js:2649 templates/js/translated/company.js:959
|
#: templates/js/translated/build.js:2650 templates/js/translated/company.js:959
|
||||||
#: templates/js/translated/part.js:596 templates/js/translated/part.js:599
|
#: templates/js/translated/part.js:596 templates/js/translated/part.js:599
|
||||||
#: templates/js/translated/table_filters.js:178
|
#: templates/js/translated/table_filters.js:178
|
||||||
msgid "Available"
|
msgid "Available"
|
||||||
@@ -3063,7 +3075,7 @@ msgid "New Sales Order"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: company/templates/company/detail.html:168
|
#: company/templates/company/detail.html:168
|
||||||
#: templates/js/translated/build.js:1657
|
#: templates/js/translated/build.js:1658
|
||||||
msgid "Assigned Stock"
|
msgid "Assigned Stock"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -3985,8 +3997,8 @@ msgstr ""
|
|||||||
#: part/templates/part/import_wizard/ajax_match_fields.html:64
|
#: part/templates/part/import_wizard/ajax_match_fields.html:64
|
||||||
#: part/templates/part/import_wizard/ajax_match_references.html:42
|
#: part/templates/part/import_wizard/ajax_match_references.html:42
|
||||||
#: part/templates/part/import_wizard/match_references.html:49
|
#: part/templates/part/import_wizard/match_references.html:49
|
||||||
#: templates/js/translated/bom.js:77 templates/js/translated/build.js:427
|
#: templates/js/translated/bom.js:77 templates/js/translated/build.js:428
|
||||||
#: templates/js/translated/build.js:579 templates/js/translated/build.js:1971
|
#: templates/js/translated/build.js:580 templates/js/translated/build.js:1972
|
||||||
#: templates/js/translated/order.js:833 templates/js/translated/order.js:1265
|
#: templates/js/translated/order.js:833 templates/js/translated/order.js:1265
|
||||||
#: templates/js/translated/order.js:2742 templates/js/translated/stock.js:621
|
#: templates/js/translated/order.js:2742 templates/js/translated/stock.js:621
|
||||||
#: templates/js/translated/stock.js:789
|
#: templates/js/translated/stock.js:789
|
||||||
@@ -4109,7 +4121,7 @@ msgstr ""
|
|||||||
|
|
||||||
#: order/templates/order/sales_order_detail.html:72
|
#: order/templates/order/sales_order_detail.html:72
|
||||||
#: templates/attachment_table.html:6 templates/js/translated/bom.js:1047
|
#: templates/attachment_table.html:6 templates/js/translated/bom.js:1047
|
||||||
#: templates/js/translated/build.js:1879
|
#: templates/js/translated/build.js:1880
|
||||||
msgid "Actions"
|
msgid "Actions"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -4167,19 +4179,19 @@ msgstr ""
|
|||||||
msgid "This option must be selected"
|
msgid "This option must be selected"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: part/api.py:1073
|
#: part/api.py:1074
|
||||||
msgid "Must be greater than zero"
|
msgid "Must be greater than zero"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: part/api.py:1077
|
#: part/api.py:1078
|
||||||
msgid "Must be a valid quantity"
|
msgid "Must be a valid quantity"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: part/api.py:1092
|
#: part/api.py:1093
|
||||||
msgid "Specify location for initial part stock"
|
msgid "Specify location for initial part stock"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: part/api.py:1123 part/api.py:1127 part/api.py:1142 part/api.py:1146
|
#: part/api.py:1124 part/api.py:1128 part/api.py:1143 part/api.py:1147
|
||||||
msgid "This field is required"
|
msgid "This field is required"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -5773,8 +5785,8 @@ msgstr ""
|
|||||||
|
|
||||||
#: report/templates/report/inventree_test_report_base.html:79
|
#: report/templates/report/inventree_test_report_base.html:79
|
||||||
#: stock/models.py:641 stock/templates/stock/item_base.html:322
|
#: stock/models.py:641 stock/templates/stock/item_base.html:322
|
||||||
#: templates/js/translated/build.js:420 templates/js/translated/build.js:572
|
#: templates/js/translated/build.js:421 templates/js/translated/build.js:573
|
||||||
#: templates/js/translated/build.js:1173 templates/js/translated/build.js:1670
|
#: templates/js/translated/build.js:1174 templates/js/translated/build.js:1671
|
||||||
#: templates/js/translated/model_renderers.js:118
|
#: templates/js/translated/model_renderers.js:118
|
||||||
#: templates/js/translated/order.js:115 templates/js/translated/order.js:3240
|
#: templates/js/translated/order.js:115 templates/js/translated/order.js:3240
|
||||||
#: templates/js/translated/order.js:3329 templates/js/translated/stock.js:486
|
#: templates/js/translated/order.js:3329 templates/js/translated/stock.js:486
|
||||||
@@ -6395,7 +6407,7 @@ msgid "Available Quantity"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: stock/templates/stock/item_base.html:394
|
#: stock/templates/stock/item_base.html:394
|
||||||
#: templates/js/translated/build.js:1692
|
#: templates/js/translated/build.js:1693
|
||||||
msgid "No location set"
|
msgid "No location set"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -6808,7 +6820,7 @@ msgid "Plugin Settings"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/InvenTree/settings/plugin.html:16
|
#: templates/InvenTree/settings/plugin.html:16
|
||||||
msgid "Changing the settings below require you to immediatly restart the server. Do not change this while under active usage."
|
msgid "Changing the settings below require you to immediately restart the server. Do not change this while under active usage."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/InvenTree/settings/plugin.html:34
|
#: templates/InvenTree/settings/plugin.html:34
|
||||||
@@ -7689,19 +7701,19 @@ msgstr ""
|
|||||||
msgid "No attachments found"
|
msgid "No attachments found"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/attachment.js:218
|
#: templates/js/translated/attachment.js:219
|
||||||
msgid "Edit Attachment"
|
msgid "Edit Attachment"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/attachment.js:287
|
#: templates/js/translated/attachment.js:289
|
||||||
msgid "Upload Date"
|
msgid "Upload Date"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/attachment.js:310
|
#: templates/js/translated/attachment.js:312
|
||||||
msgid "Edit attachment"
|
msgid "Edit attachment"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/attachment.js:319
|
#: templates/js/translated/attachment.js:321
|
||||||
msgid "Delete attachment"
|
msgid "Delete attachment"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -7921,25 +7933,25 @@ msgstr ""
|
|||||||
msgid "Substitutes Available"
|
msgid "Substitutes Available"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/bom.js:832 templates/js/translated/build.js:1768
|
#: templates/js/translated/bom.js:832 templates/js/translated/build.js:1769
|
||||||
msgid "Variant stock allowed"
|
msgid "Variant stock allowed"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/bom.js:900 templates/js/translated/build.js:1813
|
#: templates/js/translated/bom.js:900 templates/js/translated/build.js:1814
|
||||||
#: templates/js/translated/order.js:3577
|
#: templates/js/translated/order.js:3577
|
||||||
msgid "No Stock Available"
|
msgid "No Stock Available"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/bom.js:904 templates/js/translated/build.js:1817
|
#: templates/js/translated/bom.js:904 templates/js/translated/build.js:1818
|
||||||
msgid "Includes variant and substitute stock"
|
msgid "Includes variant and substitute stock"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/bom.js:906 templates/js/translated/build.js:1819
|
#: templates/js/translated/bom.js:906 templates/js/translated/build.js:1820
|
||||||
#: templates/js/translated/part.js:759
|
#: templates/js/translated/part.js:759
|
||||||
msgid "Includes variant stock"
|
msgid "Includes variant stock"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/bom.js:908 templates/js/translated/build.js:1821
|
#: templates/js/translated/bom.js:908 templates/js/translated/build.js:1822
|
||||||
msgid "Includes substitute stock"
|
msgid "Includes substitute stock"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -7979,11 +7991,11 @@ msgstr ""
|
|||||||
msgid "Delete BOM Item"
|
msgid "Delete BOM Item"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/bom.js:1158 templates/js/translated/build.js:1614
|
#: templates/js/translated/bom.js:1158 templates/js/translated/build.js:1615
|
||||||
msgid "No BOM items found"
|
msgid "No BOM items found"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/bom.js:1402 templates/js/translated/build.js:1752
|
#: templates/js/translated/bom.js:1402 templates/js/translated/build.js:1753
|
||||||
msgid "Required Part"
|
msgid "Required Part"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -8015,256 +8027,256 @@ msgstr ""
|
|||||||
msgid "There are incomplete outputs remaining for this build order"
|
msgid "There are incomplete outputs remaining for this build order"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:185
|
#: templates/js/translated/build.js:186
|
||||||
msgid "Build order is ready to be completed"
|
msgid "Build order is ready to be completed"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:190
|
#: templates/js/translated/build.js:191
|
||||||
msgid "Build Order is incomplete"
|
msgid "Build Order is incomplete"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:218
|
#: templates/js/translated/build.js:219
|
||||||
msgid "Complete Build Order"
|
msgid "Complete Build Order"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:259 templates/js/translated/stock.js:92
|
#: templates/js/translated/build.js:260 templates/js/translated/stock.js:92
|
||||||
#: templates/js/translated/stock.js:210
|
#: templates/js/translated/stock.js:210
|
||||||
msgid "Next available serial number"
|
msgid "Next available serial number"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:261 templates/js/translated/stock.js:94
|
#: templates/js/translated/build.js:262 templates/js/translated/stock.js:94
|
||||||
#: templates/js/translated/stock.js:212
|
#: templates/js/translated/stock.js:212
|
||||||
msgid "Latest serial number"
|
msgid "Latest serial number"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:270
|
#: templates/js/translated/build.js:271
|
||||||
msgid "The Bill of Materials contains trackable parts"
|
msgid "The Bill of Materials contains trackable parts"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:271
|
#: templates/js/translated/build.js:272
|
||||||
msgid "Build outputs must be generated individually"
|
msgid "Build outputs must be generated individually"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:279
|
#: templates/js/translated/build.js:280
|
||||||
msgid "Trackable parts can have serial numbers specified"
|
msgid "Trackable parts can have serial numbers specified"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:280
|
#: templates/js/translated/build.js:281
|
||||||
msgid "Enter serial numbers to generate multiple single build outputs"
|
msgid "Enter serial numbers to generate multiple single build outputs"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:287
|
#: templates/js/translated/build.js:288
|
||||||
msgid "Create Build Output"
|
msgid "Create Build Output"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:318
|
#: templates/js/translated/build.js:319
|
||||||
msgid "Allocate stock items to this build output"
|
msgid "Allocate stock items to this build output"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:329
|
#: templates/js/translated/build.js:330
|
||||||
msgid "Unallocate stock from build output"
|
msgid "Unallocate stock from build output"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:338
|
#: templates/js/translated/build.js:339
|
||||||
msgid "Complete build output"
|
msgid "Complete build output"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:346
|
#: templates/js/translated/build.js:347
|
||||||
msgid "Delete build output"
|
msgid "Delete build output"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:369
|
#: templates/js/translated/build.js:370
|
||||||
msgid "Are you sure you wish to unallocate stock items from this build?"
|
msgid "Are you sure you wish to unallocate stock items from this build?"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:387
|
#: templates/js/translated/build.js:388
|
||||||
msgid "Unallocate Stock Items"
|
msgid "Unallocate Stock Items"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:407 templates/js/translated/build.js:559
|
#: templates/js/translated/build.js:408 templates/js/translated/build.js:560
|
||||||
msgid "Select Build Outputs"
|
msgid "Select Build Outputs"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:408 templates/js/translated/build.js:560
|
#: templates/js/translated/build.js:409 templates/js/translated/build.js:561
|
||||||
msgid "At least one build output must be selected"
|
msgid "At least one build output must be selected"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:462 templates/js/translated/build.js:614
|
#: templates/js/translated/build.js:463 templates/js/translated/build.js:615
|
||||||
msgid "Output"
|
msgid "Output"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:480
|
#: templates/js/translated/build.js:481
|
||||||
msgid "Complete Build Outputs"
|
msgid "Complete Build Outputs"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:627
|
#: templates/js/translated/build.js:628
|
||||||
msgid "Delete Build Outputs"
|
msgid "Delete Build Outputs"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:716
|
#: templates/js/translated/build.js:717
|
||||||
msgid "No build order allocations found"
|
msgid "No build order allocations found"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:754
|
#: templates/js/translated/build.js:755
|
||||||
msgid "Location not specified"
|
msgid "Location not specified"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:1133
|
#: templates/js/translated/build.js:1134
|
||||||
msgid "No active build outputs found"
|
msgid "No active build outputs found"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:1202
|
#: templates/js/translated/build.js:1203
|
||||||
msgid "Allocated Stock"
|
msgid "Allocated Stock"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:1209
|
#: templates/js/translated/build.js:1210
|
||||||
msgid "No tracked BOM items for this build"
|
msgid "No tracked BOM items for this build"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:1231
|
#: templates/js/translated/build.js:1232
|
||||||
msgid "Completed Tests"
|
msgid "Completed Tests"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:1236
|
#: templates/js/translated/build.js:1237
|
||||||
msgid "No required tests for this build"
|
msgid "No required tests for this build"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:1709 templates/js/translated/build.js:2660
|
#: templates/js/translated/build.js:1710 templates/js/translated/build.js:2661
|
||||||
#: templates/js/translated/order.js:3277
|
#: templates/js/translated/order.js:3277
|
||||||
msgid "Edit stock allocation"
|
msgid "Edit stock allocation"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:1711 templates/js/translated/build.js:2661
|
#: templates/js/translated/build.js:1712 templates/js/translated/build.js:2662
|
||||||
#: templates/js/translated/order.js:3278
|
#: templates/js/translated/order.js:3278
|
||||||
msgid "Delete stock allocation"
|
msgid "Delete stock allocation"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:1729
|
#: templates/js/translated/build.js:1730
|
||||||
msgid "Edit Allocation"
|
msgid "Edit Allocation"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:1739
|
#: templates/js/translated/build.js:1740
|
||||||
msgid "Remove Allocation"
|
msgid "Remove Allocation"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:1764
|
#: templates/js/translated/build.js:1765
|
||||||
msgid "Substitute parts available"
|
msgid "Substitute parts available"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:1781
|
#: templates/js/translated/build.js:1782
|
||||||
msgid "Quantity Per"
|
msgid "Quantity Per"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:1807 templates/js/translated/order.js:3584
|
#: templates/js/translated/build.js:1808 templates/js/translated/order.js:3584
|
||||||
msgid "Insufficient stock available"
|
msgid "Insufficient stock available"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:1809 templates/js/translated/order.js:3582
|
#: templates/js/translated/build.js:1810 templates/js/translated/order.js:3582
|
||||||
msgid "Sufficient stock available"
|
msgid "Sufficient stock available"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:1838 templates/js/translated/build.js:2083
|
#: templates/js/translated/build.js:1839 templates/js/translated/build.js:2084
|
||||||
#: templates/js/translated/build.js:2656 templates/js/translated/order.js:3596
|
#: templates/js/translated/build.js:2657 templates/js/translated/order.js:3596
|
||||||
msgid "Allocated"
|
msgid "Allocated"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:1886 templates/js/translated/order.js:3676
|
#: templates/js/translated/build.js:1887 templates/js/translated/order.js:3676
|
||||||
msgid "Build stock"
|
msgid "Build stock"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:1890 templates/stock_table.html:50
|
#: templates/js/translated/build.js:1891 templates/stock_table.html:50
|
||||||
msgid "Order stock"
|
msgid "Order stock"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:1893 templates/js/translated/order.js:3669
|
#: templates/js/translated/build.js:1894 templates/js/translated/order.js:3669
|
||||||
msgid "Allocate stock"
|
msgid "Allocate stock"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:1932 templates/js/translated/label.js:172
|
#: templates/js/translated/build.js:1933 templates/js/translated/label.js:172
|
||||||
#: templates/js/translated/order.js:756 templates/js/translated/order.js:2804
|
#: templates/js/translated/order.js:756 templates/js/translated/order.js:2804
|
||||||
#: templates/js/translated/report.js:225
|
#: templates/js/translated/report.js:225
|
||||||
msgid "Select Parts"
|
msgid "Select Parts"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:1933 templates/js/translated/order.js:2805
|
#: templates/js/translated/build.js:1934 templates/js/translated/order.js:2805
|
||||||
msgid "You must select at least one part to allocate"
|
msgid "You must select at least one part to allocate"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:1982 templates/js/translated/order.js:2753
|
#: templates/js/translated/build.js:1983 templates/js/translated/order.js:2753
|
||||||
msgid "Specify stock allocation quantity"
|
msgid "Specify stock allocation quantity"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:2056
|
#: templates/js/translated/build.js:2057
|
||||||
msgid "All Parts Allocated"
|
msgid "All Parts Allocated"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:2057
|
#: templates/js/translated/build.js:2058
|
||||||
msgid "All selected parts have been fully allocated"
|
msgid "All selected parts have been fully allocated"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:2071 templates/js/translated/order.js:2819
|
#: templates/js/translated/build.js:2072 templates/js/translated/order.js:2819
|
||||||
msgid "Select source location (leave blank to take from all locations)"
|
msgid "Select source location (leave blank to take from all locations)"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:2099
|
#: templates/js/translated/build.js:2100
|
||||||
msgid "Allocate Stock Items to Build Order"
|
msgid "Allocate Stock Items to Build Order"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:2110 templates/js/translated/order.js:2916
|
#: templates/js/translated/build.js:2111 templates/js/translated/order.js:2916
|
||||||
msgid "No matching stock locations"
|
msgid "No matching stock locations"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:2182 templates/js/translated/order.js:2993
|
#: templates/js/translated/build.js:2183 templates/js/translated/order.js:2993
|
||||||
msgid "No matching stock items"
|
msgid "No matching stock items"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:2279
|
#: templates/js/translated/build.js:2280
|
||||||
msgid "Automatic Stock Allocation"
|
msgid "Automatic Stock Allocation"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:2280
|
#: templates/js/translated/build.js:2281
|
||||||
msgid "Stock items will be automatically allocated to this build order, according to the provided guidelines"
|
msgid "Stock items will be automatically allocated to this build order, according to the provided guidelines"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:2282
|
#: templates/js/translated/build.js:2283
|
||||||
msgid "If a location is specifed, stock will only be allocated from that location"
|
msgid "If a location is specifed, stock will only be allocated from that location"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:2283
|
#: templates/js/translated/build.js:2284
|
||||||
msgid "If stock is considered interchangeable, it will be allocated from the first location it is found"
|
msgid "If stock is considered interchangeable, it will be allocated from the first location it is found"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:2284
|
#: templates/js/translated/build.js:2285
|
||||||
msgid "If substitute stock is allowed, it will be used where stock of the primary part cannot be found"
|
msgid "If substitute stock is allowed, it will be used where stock of the primary part cannot be found"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:2305
|
#: templates/js/translated/build.js:2306
|
||||||
msgid "Allocate Stock Items"
|
msgid "Allocate Stock Items"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:2412
|
#: templates/js/translated/build.js:2413
|
||||||
msgid "No builds matching query"
|
msgid "No builds matching query"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:2447 templates/js/translated/part.js:1383
|
#: templates/js/translated/build.js:2448 templates/js/translated/part.js:1383
|
||||||
#: templates/js/translated/part.js:1850 templates/js/translated/stock.js:1682
|
#: templates/js/translated/part.js:1850 templates/js/translated/stock.js:1682
|
||||||
#: templates/js/translated/stock.js:2340
|
#: templates/js/translated/stock.js:2340
|
||||||
msgid "Select"
|
msgid "Select"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:2467
|
#: templates/js/translated/build.js:2468
|
||||||
msgid "Build order is overdue"
|
msgid "Build order is overdue"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:2495
|
#: templates/js/translated/build.js:2496
|
||||||
msgid "Progress"
|
msgid "Progress"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:2531 templates/js/translated/stock.js:2582
|
#: templates/js/translated/build.js:2532 templates/js/translated/stock.js:2582
|
||||||
msgid "No user information"
|
msgid "No user information"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:2637
|
#: templates/js/translated/build.js:2638
|
||||||
msgid "No parts allocated for"
|
msgid "No parts allocated for"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -10058,61 +10070,61 @@ msgstr ""
|
|||||||
msgid "Select File Format"
|
msgid "Select File Format"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/tables.js:534
|
#: templates/js/translated/tables.js:535
|
||||||
msgid "Loading data"
|
msgid "Loading data"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/tables.js:537
|
#: templates/js/translated/tables.js:538
|
||||||
msgid "rows per page"
|
msgid "rows per page"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/tables.js:542
|
#: templates/js/translated/tables.js:543
|
||||||
msgid "Showing all rows"
|
msgid "Showing all rows"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/tables.js:544
|
#: templates/js/translated/tables.js:545
|
||||||
msgid "Showing"
|
msgid "Showing"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/tables.js:544
|
#: templates/js/translated/tables.js:545
|
||||||
msgid "to"
|
msgid "to"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/tables.js:544
|
#: templates/js/translated/tables.js:545
|
||||||
msgid "of"
|
msgid "of"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/tables.js:544
|
#: templates/js/translated/tables.js:545
|
||||||
msgid "rows"
|
msgid "rows"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/tables.js:548 templates/navbar.html:102
|
#: templates/js/translated/tables.js:549 templates/navbar.html:102
|
||||||
#: templates/search.html:8 templates/search_form.html:6
|
#: templates/search.html:8 templates/search_form.html:6
|
||||||
#: templates/search_form.html:7
|
#: templates/search_form.html:7
|
||||||
msgid "Search"
|
msgid "Search"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/tables.js:551
|
#: templates/js/translated/tables.js:552
|
||||||
msgid "No matching results"
|
msgid "No matching results"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/tables.js:554
|
#: templates/js/translated/tables.js:555
|
||||||
msgid "Hide/Show pagination"
|
msgid "Hide/Show pagination"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/tables.js:557
|
#: templates/js/translated/tables.js:558
|
||||||
msgid "Refresh"
|
msgid "Refresh"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/tables.js:560
|
#: templates/js/translated/tables.js:561
|
||||||
msgid "Toggle"
|
msgid "Toggle"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/tables.js:563
|
#: templates/js/translated/tables.js:564
|
||||||
msgid "Columns"
|
msgid "Columns"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/tables.js:566
|
#: templates/js/translated/tables.js:567
|
||||||
msgid "All"
|
msgid "All"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -8,7 +8,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2022-06-28 12:13+0000\n"
|
"POT-Creation-Date: 2022-07-04 02:07+0000\n"
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
@@ -141,7 +141,7 @@ msgstr ""
|
|||||||
|
|
||||||
#: InvenTree/models.py:191 stock/models.py:2096
|
#: InvenTree/models.py:191 stock/models.py:2096
|
||||||
#: templates/js/translated/attachment.js:103
|
#: templates/js/translated/attachment.js:103
|
||||||
#: templates/js/translated/attachment.js:239
|
#: templates/js/translated/attachment.js:240
|
||||||
msgid "Attachment"
|
msgid "Attachment"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -165,7 +165,7 @@ msgid "Link to external URL"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: InvenTree/models.py:202 templates/js/translated/attachment.js:104
|
#: InvenTree/models.py:202 templates/js/translated/attachment.js:104
|
||||||
#: templates/js/translated/attachment.js:283
|
#: templates/js/translated/attachment.js:284
|
||||||
msgid "Comment"
|
msgid "Comment"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -243,7 +243,7 @@ msgstr ""
|
|||||||
#: stock/templates/stock/location.html:103
|
#: stock/templates/stock/location.html:103
|
||||||
#: templates/InvenTree/settings/plugin_settings.html:33
|
#: templates/InvenTree/settings/plugin_settings.html:33
|
||||||
#: templates/js/translated/bom.js:553 templates/js/translated/bom.js:845
|
#: templates/js/translated/bom.js:553 templates/js/translated/bom.js:845
|
||||||
#: templates/js/translated/build.js:2475 templates/js/translated/company.js:397
|
#: templates/js/translated/build.js:2476 templates/js/translated/company.js:397
|
||||||
#: templates/js/translated/company.js:653
|
#: templates/js/translated/company.js:653
|
||||||
#: templates/js/translated/company.js:944 templates/js/translated/order.js:1656
|
#: templates/js/translated/company.js:944 templates/js/translated/order.js:1656
|
||||||
#: templates/js/translated/order.js:1888 templates/js/translated/order.js:2476
|
#: templates/js/translated/order.js:1888 templates/js/translated/order.js:2476
|
||||||
@@ -656,7 +656,7 @@ msgstr ""
|
|||||||
#: report/templates/report/inventree_build_order_base.html:106
|
#: report/templates/report/inventree_build_order_base.html:106
|
||||||
#: templates/email/build_order_completed.html:16
|
#: templates/email/build_order_completed.html:16
|
||||||
#: templates/email/overdue_build_order.html:15
|
#: templates/email/overdue_build_order.html:15
|
||||||
#: templates/js/translated/build.js:727
|
#: templates/js/translated/build.js:728
|
||||||
msgid "Build Order"
|
msgid "Build Order"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -680,7 +680,7 @@ msgstr ""
|
|||||||
#: report/templates/report/inventree_po_report.html:91
|
#: report/templates/report/inventree_po_report.html:91
|
||||||
#: report/templates/report/inventree_so_report.html:92
|
#: report/templates/report/inventree_so_report.html:92
|
||||||
#: templates/js/translated/bom.js:690 templates/js/translated/bom.js:852
|
#: templates/js/translated/bom.js:690 templates/js/translated/bom.js:852
|
||||||
#: templates/js/translated/build.js:1776 templates/js/translated/order.js:1919
|
#: templates/js/translated/build.js:1777 templates/js/translated/order.js:1919
|
||||||
#: templates/js/translated/order.js:2120 templates/js/translated/order.js:3468
|
#: templates/js/translated/order.js:2120 templates/js/translated/order.js:3468
|
||||||
#: templates/js/translated/order.js:3976
|
#: templates/js/translated/order.js:3976
|
||||||
msgid "Reference"
|
msgid "Reference"
|
||||||
@@ -719,8 +719,8 @@ msgstr ""
|
|||||||
#: templates/email/overdue_build_order.html:16
|
#: templates/email/overdue_build_order.html:16
|
||||||
#: templates/js/translated/barcode.js:435 templates/js/translated/bom.js:552
|
#: templates/js/translated/barcode.js:435 templates/js/translated/bom.js:552
|
||||||
#: templates/js/translated/bom.js:689 templates/js/translated/bom.js:799
|
#: templates/js/translated/bom.js:689 templates/js/translated/bom.js:799
|
||||||
#: templates/js/translated/build.js:1153 templates/js/translated/build.js:1646
|
#: templates/js/translated/build.js:1154 templates/js/translated/build.js:1647
|
||||||
#: templates/js/translated/build.js:2082 templates/js/translated/build.js:2480
|
#: templates/js/translated/build.js:2083 templates/js/translated/build.js:2481
|
||||||
#: templates/js/translated/company.js:255
|
#: templates/js/translated/company.js:255
|
||||||
#: templates/js/translated/company.js:484
|
#: templates/js/translated/company.js:484
|
||||||
#: templates/js/translated/company.js:594
|
#: templates/js/translated/company.js:594
|
||||||
@@ -748,8 +748,8 @@ msgstr ""
|
|||||||
msgid "SalesOrder to which this build is allocated"
|
msgid "SalesOrder to which this build is allocated"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/models.py:236 build/serializers.py:758
|
#: build/models.py:236 build/serializers.py:774
|
||||||
#: templates/js/translated/build.js:2070 templates/js/translated/order.js:2818
|
#: templates/js/translated/build.js:2071 templates/js/translated/order.js:2818
|
||||||
msgid "Source Location"
|
msgid "Source Location"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -812,7 +812,7 @@ msgid "Target date for build completion. Build will be overdue after this date."
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/models.py:289 order/models.py:323
|
#: build/models.py:289 order/models.py:323
|
||||||
#: templates/js/translated/build.js:2557
|
#: templates/js/translated/build.js:2558
|
||||||
msgid "Completion Date"
|
msgid "Completion Date"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -820,7 +820,7 @@ msgstr ""
|
|||||||
msgid "completed by"
|
msgid "completed by"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/models.py:303 templates/js/translated/build.js:2525
|
#: build/models.py:303 templates/js/translated/build.js:2526
|
||||||
msgid "Issued by"
|
msgid "Issued by"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -833,7 +833,7 @@ msgstr ""
|
|||||||
#: order/templates/order/order_base.html:176
|
#: order/templates/order/order_base.html:176
|
||||||
#: order/templates/order/sales_order_base.html:183 part/models.py:935
|
#: order/templates/order/sales_order_base.html:183 part/models.py:935
|
||||||
#: report/templates/report/inventree_build_order_base.html:159
|
#: report/templates/report/inventree_build_order_base.html:159
|
||||||
#: templates/js/translated/build.js:2537 templates/js/translated/order.js:1690
|
#: templates/js/translated/build.js:2538 templates/js/translated/order.js:1690
|
||||||
msgid "Responsible"
|
msgid "Responsible"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -874,48 +874,48 @@ msgstr ""
|
|||||||
msgid "Build output does not match Build Order"
|
msgid "Build output does not match Build Order"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/models.py:1148
|
#: build/models.py:1162
|
||||||
msgid "Build item must specify a build output, as master part is marked as trackable"
|
msgid "Build item must specify a build output, as master part is marked as trackable"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/models.py:1157
|
#: build/models.py:1171
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Allocated quantity ({q}) must not exceed available stock quantity ({a})"
|
msgid "Allocated quantity ({q}) must not exceed available stock quantity ({a})"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/models.py:1167
|
#: build/models.py:1181
|
||||||
msgid "Stock item is over-allocated"
|
msgid "Stock item is over-allocated"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/models.py:1173 order/models.py:1404
|
#: build/models.py:1187 order/models.py:1404
|
||||||
msgid "Allocation quantity must be greater than zero"
|
msgid "Allocation quantity must be greater than zero"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/models.py:1179
|
#: build/models.py:1193
|
||||||
msgid "Quantity must be 1 for serialized stock"
|
msgid "Quantity must be 1 for serialized stock"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/models.py:1236
|
#: build/models.py:1250
|
||||||
msgid "Selected stock item not found in BOM"
|
msgid "Selected stock item not found in BOM"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/models.py:1305 stock/templates/stock/item_base.html:177
|
#: build/models.py:1319 stock/templates/stock/item_base.html:177
|
||||||
#: templates/InvenTree/search.html:137 templates/js/translated/build.js:2453
|
#: templates/InvenTree/search.html:137 templates/js/translated/build.js:2454
|
||||||
#: templates/navbar.html:38
|
#: templates/navbar.html:38
|
||||||
msgid "Build"
|
msgid "Build"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/models.py:1306
|
#: build/models.py:1320
|
||||||
msgid "Build to allocate parts"
|
msgid "Build to allocate parts"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/models.py:1322 build/serializers.py:603 order/serializers.py:996
|
#: build/models.py:1336 build/serializers.py:619 order/serializers.py:996
|
||||||
#: order/serializers.py:1017 stock/serializers.py:394 stock/serializers.py:741
|
#: order/serializers.py:1017 stock/serializers.py:394 stock/serializers.py:741
|
||||||
#: stock/serializers.py:867 stock/templates/stock/item_base.html:10
|
#: stock/serializers.py:867 stock/templates/stock/item_base.html:10
|
||||||
#: stock/templates/stock/item_base.html:23
|
#: stock/templates/stock/item_base.html:23
|
||||||
#: stock/templates/stock/item_base.html:199
|
#: stock/templates/stock/item_base.html:199
|
||||||
#: templates/js/translated/build.js:738 templates/js/translated/build.js:743
|
#: templates/js/translated/build.js:739 templates/js/translated/build.js:744
|
||||||
#: templates/js/translated/build.js:2084 templates/js/translated/build.js:2642
|
#: templates/js/translated/build.js:2085 templates/js/translated/build.js:2643
|
||||||
#: templates/js/translated/order.js:101 templates/js/translated/order.js:2831
|
#: templates/js/translated/order.js:101 templates/js/translated/order.js:2831
|
||||||
#: templates/js/translated/order.js:3135 templates/js/translated/order.js:3140
|
#: templates/js/translated/order.js:3135 templates/js/translated/order.js:3140
|
||||||
#: templates/js/translated/order.js:3235 templates/js/translated/order.js:3325
|
#: templates/js/translated/order.js:3235 templates/js/translated/order.js:3325
|
||||||
@@ -924,11 +924,11 @@ msgstr ""
|
|||||||
msgid "Stock Item"
|
msgid "Stock Item"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/models.py:1323
|
#: build/models.py:1337
|
||||||
msgid "Source stock item"
|
msgid "Source stock item"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/models.py:1335 build/serializers.py:183
|
#: build/models.py:1349 build/serializers.py:183
|
||||||
#: build/templates/build/build_base.html:82
|
#: build/templates/build/build_base.html:82
|
||||||
#: build/templates/build/detail.html:34 common/models.py:1644
|
#: build/templates/build/detail.html:34 common/models.py:1644
|
||||||
#: company/forms.py:36 company/templates/company/supplier_part.html:279
|
#: company/forms.py:36 company/templates/company/supplier_part.html:279
|
||||||
@@ -947,10 +947,10 @@ msgstr ""
|
|||||||
#: stock/templates/stock/item_base.html:300
|
#: stock/templates/stock/item_base.html:300
|
||||||
#: templates/email/build_order_completed.html:18
|
#: templates/email/build_order_completed.html:18
|
||||||
#: templates/js/translated/barcode.js:437 templates/js/translated/bom.js:691
|
#: templates/js/translated/barcode.js:437 templates/js/translated/bom.js:691
|
||||||
#: templates/js/translated/bom.js:860 templates/js/translated/build.js:422
|
#: templates/js/translated/bom.js:860 templates/js/translated/build.js:423
|
||||||
#: templates/js/translated/build.js:574 templates/js/translated/build.js:765
|
#: templates/js/translated/build.js:575 templates/js/translated/build.js:766
|
||||||
#: templates/js/translated/build.js:1175 templates/js/translated/build.js:1672
|
#: templates/js/translated/build.js:1176 templates/js/translated/build.js:1673
|
||||||
#: templates/js/translated/build.js:2085
|
#: templates/js/translated/build.js:2086
|
||||||
#: templates/js/translated/model_renderers.js:120
|
#: templates/js/translated/model_renderers.js:120
|
||||||
#: templates/js/translated/order.js:117 templates/js/translated/order.js:886
|
#: templates/js/translated/order.js:117 templates/js/translated/order.js:886
|
||||||
#: templates/js/translated/order.js:1925 templates/js/translated/order.js:2126
|
#: templates/js/translated/order.js:1925 templates/js/translated/order.js:2126
|
||||||
@@ -965,20 +965,20 @@ msgstr ""
|
|||||||
msgid "Quantity"
|
msgid "Quantity"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/models.py:1336
|
#: build/models.py:1350
|
||||||
msgid "Stock quantity to allocate to build"
|
msgid "Stock quantity to allocate to build"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/models.py:1344
|
#: build/models.py:1358
|
||||||
msgid "Install into"
|
msgid "Install into"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/models.py:1345
|
#: build/models.py:1359
|
||||||
msgid "Destination stock item"
|
msgid "Destination stock item"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/serializers.py:128 build/serializers.py:632
|
#: build/serializers.py:128 build/serializers.py:648
|
||||||
#: templates/js/translated/build.js:1163
|
#: templates/js/translated/build.js:1164
|
||||||
msgid "Build Output"
|
msgid "Build Output"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -1002,7 +1002,7 @@ msgstr ""
|
|||||||
msgid "Enter quantity for build output"
|
msgid "Enter quantity for build output"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/serializers.py:198 build/serializers.py:623 order/models.py:355
|
#: build/serializers.py:198 build/serializers.py:639 order/models.py:355
|
||||||
#: order/serializers.py:280 order/serializers.py:435 part/serializers.py:503
|
#: order/serializers.py:280 order/serializers.py:435 part/serializers.py:503
|
||||||
#: part/serializers.py:926 stock/models.py:478 stock/models.py:1244
|
#: part/serializers.py:926 stock/models.py:478 stock/models.py:1244
|
||||||
#: stock/serializers.py:300
|
#: stock/serializers.py:300
|
||||||
@@ -1048,8 +1048,8 @@ msgstr ""
|
|||||||
#: stock/serializers.py:902 stock/serializers.py:1135
|
#: stock/serializers.py:902 stock/serializers.py:1135
|
||||||
#: stock/templates/stock/item_base.html:390
|
#: stock/templates/stock/item_base.html:390
|
||||||
#: templates/js/translated/barcode.js:436
|
#: templates/js/translated/barcode.js:436
|
||||||
#: templates/js/translated/barcode.js:618 templates/js/translated/build.js:750
|
#: templates/js/translated/barcode.js:618 templates/js/translated/build.js:751
|
||||||
#: templates/js/translated/build.js:1684 templates/js/translated/order.js:1213
|
#: templates/js/translated/build.js:1685 templates/js/translated/order.js:1213
|
||||||
#: templates/js/translated/order.js:3147 templates/js/translated/order.js:3250
|
#: templates/js/translated/order.js:3147 templates/js/translated/order.js:3250
|
||||||
#: templates/js/translated/order.js:3258 templates/js/translated/order.js:3339
|
#: templates/js/translated/order.js:3258 templates/js/translated/order.js:3339
|
||||||
#: templates/js/translated/part.js:181 templates/js/translated/stock.js:584
|
#: templates/js/translated/part.js:181 templates/js/translated/stock.js:584
|
||||||
@@ -1065,7 +1065,7 @@ msgstr ""
|
|||||||
#: build/serializers.py:363 build/templates/build/build_base.html:142
|
#: build/serializers.py:363 build/templates/build/build_base.html:142
|
||||||
#: build/templates/build/detail.html:62 order/models.py:665
|
#: build/templates/build/detail.html:62 order/models.py:665
|
||||||
#: order/serializers.py:458 stock/templates/stock/item_base.html:423
|
#: order/serializers.py:458 stock/templates/stock/item_base.html:423
|
||||||
#: templates/js/translated/barcode.js:182 templates/js/translated/build.js:2509
|
#: templates/js/translated/barcode.js:182 templates/js/translated/build.js:2510
|
||||||
#: templates/js/translated/order.js:1320 templates/js/translated/order.js:1660
|
#: templates/js/translated/order.js:1320 templates/js/translated/order.js:1660
|
||||||
#: templates/js/translated/order.js:2481 templates/js/translated/stock.js:1825
|
#: templates/js/translated/order.js:2481 templates/js/translated/stock.js:1825
|
||||||
#: templates/js/translated/stock.js:2530 templates/js/translated/stock.js:2662
|
#: templates/js/translated/stock.js:2530 templates/js/translated/stock.js:2662
|
||||||
@@ -1097,104 +1097,116 @@ msgid "Delete any build outputs which have not been completed"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/serializers.py:470
|
#: build/serializers.py:470
|
||||||
msgid "Accept Unallocated"
|
msgid "Accept Overallocated"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/serializers.py:471
|
#: build/serializers.py:471
|
||||||
msgid "Accept that stock items have not been fully allocated to this build order"
|
msgid "Accept stock items which have been overallocated to this build order"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/serializers.py:481 templates/js/translated/build.js:195
|
#: build/serializers.py:481
|
||||||
msgid "Required stock has not been fully allocated"
|
msgid "Some stock items have been overallocated"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/serializers.py:486
|
#: build/serializers.py:486
|
||||||
msgid "Accept Incomplete"
|
msgid "Accept Unallocated"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/serializers.py:487
|
#: build/serializers.py:487
|
||||||
|
msgid "Accept that stock items have not been fully allocated to this build order"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: build/serializers.py:497 templates/js/translated/build.js:196
|
||||||
|
msgid "Required stock has not been fully allocated"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: build/serializers.py:502
|
||||||
|
msgid "Accept Incomplete"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: build/serializers.py:503
|
||||||
msgid "Accept that the required number of build outputs have not been completed"
|
msgid "Accept that the required number of build outputs have not been completed"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/serializers.py:497 templates/js/translated/build.js:199
|
#: build/serializers.py:513 templates/js/translated/build.js:200
|
||||||
msgid "Required build quantity has not been completed"
|
msgid "Required build quantity has not been completed"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/serializers.py:506
|
#: build/serializers.py:522
|
||||||
msgid "Build order has incomplete outputs"
|
msgid "Build order has incomplete outputs"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/serializers.py:509 build/templates/build/build_base.html:95
|
#: build/serializers.py:525 build/templates/build/build_base.html:95
|
||||||
msgid "No build outputs have been created for this build order"
|
msgid "No build outputs have been created for this build order"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/serializers.py:535 build/serializers.py:580 part/models.py:2719
|
#: build/serializers.py:551 build/serializers.py:596 part/models.py:2719
|
||||||
#: part/models.py:2853
|
#: part/models.py:2853
|
||||||
msgid "BOM Item"
|
msgid "BOM Item"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/serializers.py:545
|
#: build/serializers.py:561
|
||||||
msgid "Build output"
|
msgid "Build output"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/serializers.py:553
|
#: build/serializers.py:569
|
||||||
msgid "Build output must point to the same build"
|
msgid "Build output must point to the same build"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/serializers.py:594
|
#: build/serializers.py:610
|
||||||
msgid "bom_item.part must point to the same part as the build order"
|
msgid "bom_item.part must point to the same part as the build order"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/serializers.py:609 stock/serializers.py:754
|
#: build/serializers.py:625 stock/serializers.py:754
|
||||||
msgid "Item must be in stock"
|
msgid "Item must be in stock"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/serializers.py:667 order/serializers.py:1054
|
#: build/serializers.py:683 order/serializers.py:1054
|
||||||
#, python-brace-format
|
#, python-brace-format
|
||||||
msgid "Available quantity ({q}) exceeded"
|
msgid "Available quantity ({q}) exceeded"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/serializers.py:673
|
#: build/serializers.py:689
|
||||||
msgid "Build output must be specified for allocation of tracked parts"
|
msgid "Build output must be specified for allocation of tracked parts"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/serializers.py:680
|
#: build/serializers.py:696
|
||||||
msgid "Build output cannot be specified for allocation of untracked parts"
|
msgid "Build output cannot be specified for allocation of untracked parts"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/serializers.py:685
|
#: build/serializers.py:701
|
||||||
msgid "This stock item has already been allocated to this build output"
|
msgid "This stock item has already been allocated to this build output"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/serializers.py:708 order/serializers.py:1300
|
#: build/serializers.py:724 order/serializers.py:1300
|
||||||
msgid "Allocation items must be provided"
|
msgid "Allocation items must be provided"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/serializers.py:759
|
#: build/serializers.py:775
|
||||||
msgid "Stock location where parts are to be sourced (leave blank to take from any location)"
|
msgid "Stock location where parts are to be sourced (leave blank to take from any location)"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/serializers.py:767
|
#: build/serializers.py:783
|
||||||
msgid "Exclude Location"
|
msgid "Exclude Location"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/serializers.py:768
|
#: build/serializers.py:784
|
||||||
msgid "Exclude stock items from this selected location"
|
msgid "Exclude stock items from this selected location"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/serializers.py:773
|
#: build/serializers.py:789
|
||||||
msgid "Interchangeable Stock"
|
msgid "Interchangeable Stock"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/serializers.py:774
|
#: build/serializers.py:790
|
||||||
msgid "Stock items in multiple locations can be used interchangeably"
|
msgid "Stock items in multiple locations can be used interchangeably"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/serializers.py:779
|
#: build/serializers.py:795
|
||||||
msgid "Substitute Stock"
|
msgid "Substitute Stock"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/serializers.py:780
|
#: build/serializers.py:796
|
||||||
msgid "Allow allocation of substitute parts"
|
msgid "Allow allocation of substitute parts"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -1277,7 +1289,7 @@ msgstr ""
|
|||||||
#: order/templates/order/order_base.html:162
|
#: order/templates/order/order_base.html:162
|
||||||
#: order/templates/order/sales_order_base.html:164
|
#: order/templates/order/sales_order_base.html:164
|
||||||
#: report/templates/report/inventree_build_order_base.html:126
|
#: report/templates/report/inventree_build_order_base.html:126
|
||||||
#: templates/js/translated/build.js:2549 templates/js/translated/order.js:1677
|
#: templates/js/translated/build.js:2550 templates/js/translated/order.js:1677
|
||||||
#: templates/js/translated/order.js:1987 templates/js/translated/order.js:2497
|
#: templates/js/translated/order.js:1987 templates/js/translated/order.js:2497
|
||||||
#: templates/js/translated/order.js:3537 templates/js/translated/part.js:1040
|
#: templates/js/translated/order.js:3537 templates/js/translated/part.js:1040
|
||||||
msgid "Target Date"
|
msgid "Target Date"
|
||||||
@@ -1364,7 +1376,7 @@ msgstr ""
|
|||||||
|
|
||||||
#: build/templates/build/detail.html:80
|
#: build/templates/build/detail.html:80
|
||||||
#: stock/templates/stock/item_base.html:170
|
#: stock/templates/stock/item_base.html:170
|
||||||
#: templates/js/translated/build.js:1179
|
#: templates/js/translated/build.js:1180
|
||||||
#: templates/js/translated/model_renderers.js:124
|
#: templates/js/translated/model_renderers.js:124
|
||||||
#: templates/js/translated/stock.js:1022 templates/js/translated/stock.js:1839
|
#: templates/js/translated/stock.js:1022 templates/js/translated/stock.js:1839
|
||||||
#: templates/js/translated/stock.js:2669
|
#: templates/js/translated/stock.js:2669
|
||||||
@@ -1376,7 +1388,7 @@ msgstr ""
|
|||||||
#: build/templates/build/detail.html:126
|
#: build/templates/build/detail.html:126
|
||||||
#: order/templates/order/order_base.html:149
|
#: order/templates/order/order_base.html:149
|
||||||
#: order/templates/order/sales_order_base.html:158
|
#: order/templates/order/sales_order_base.html:158
|
||||||
#: templates/js/translated/build.js:2517
|
#: templates/js/translated/build.js:2518
|
||||||
msgid "Created"
|
msgid "Created"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -1396,7 +1408,7 @@ msgstr ""
|
|||||||
msgid "Allocate Stock to Build"
|
msgid "Allocate Stock to Build"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: build/templates/build/detail.html:176 templates/js/translated/build.js:1898
|
#: build/templates/build/detail.html:176 templates/js/translated/build.js:1899
|
||||||
msgid "Unallocate stock"
|
msgid "Unallocate stock"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -2868,8 +2880,8 @@ msgstr ""
|
|||||||
#: company/models.py:538 company/templates/company/supplier_part.html:94
|
#: company/models.py:538 company/templates/company/supplier_part.html:94
|
||||||
#: templates/email/build_order_required_stock.html:19
|
#: templates/email/build_order_required_stock.html:19
|
||||||
#: templates/email/low_stock_notification.html:18
|
#: templates/email/low_stock_notification.html:18
|
||||||
#: templates/js/translated/bom.js:884 templates/js/translated/build.js:1786
|
#: templates/js/translated/bom.js:884 templates/js/translated/build.js:1787
|
||||||
#: templates/js/translated/build.js:2649 templates/js/translated/company.js:959
|
#: templates/js/translated/build.js:2650 templates/js/translated/company.js:959
|
||||||
#: templates/js/translated/part.js:596 templates/js/translated/part.js:599
|
#: templates/js/translated/part.js:596 templates/js/translated/part.js:599
|
||||||
#: templates/js/translated/table_filters.js:178
|
#: templates/js/translated/table_filters.js:178
|
||||||
msgid "Available"
|
msgid "Available"
|
||||||
@@ -3063,7 +3075,7 @@ msgid "New Sales Order"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: company/templates/company/detail.html:168
|
#: company/templates/company/detail.html:168
|
||||||
#: templates/js/translated/build.js:1657
|
#: templates/js/translated/build.js:1658
|
||||||
msgid "Assigned Stock"
|
msgid "Assigned Stock"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -3985,8 +3997,8 @@ msgstr ""
|
|||||||
#: part/templates/part/import_wizard/ajax_match_fields.html:64
|
#: part/templates/part/import_wizard/ajax_match_fields.html:64
|
||||||
#: part/templates/part/import_wizard/ajax_match_references.html:42
|
#: part/templates/part/import_wizard/ajax_match_references.html:42
|
||||||
#: part/templates/part/import_wizard/match_references.html:49
|
#: part/templates/part/import_wizard/match_references.html:49
|
||||||
#: templates/js/translated/bom.js:77 templates/js/translated/build.js:427
|
#: templates/js/translated/bom.js:77 templates/js/translated/build.js:428
|
||||||
#: templates/js/translated/build.js:579 templates/js/translated/build.js:1971
|
#: templates/js/translated/build.js:580 templates/js/translated/build.js:1972
|
||||||
#: templates/js/translated/order.js:833 templates/js/translated/order.js:1265
|
#: templates/js/translated/order.js:833 templates/js/translated/order.js:1265
|
||||||
#: templates/js/translated/order.js:2742 templates/js/translated/stock.js:621
|
#: templates/js/translated/order.js:2742 templates/js/translated/stock.js:621
|
||||||
#: templates/js/translated/stock.js:789
|
#: templates/js/translated/stock.js:789
|
||||||
@@ -4109,7 +4121,7 @@ msgstr ""
|
|||||||
|
|
||||||
#: order/templates/order/sales_order_detail.html:72
|
#: order/templates/order/sales_order_detail.html:72
|
||||||
#: templates/attachment_table.html:6 templates/js/translated/bom.js:1047
|
#: templates/attachment_table.html:6 templates/js/translated/bom.js:1047
|
||||||
#: templates/js/translated/build.js:1879
|
#: templates/js/translated/build.js:1880
|
||||||
msgid "Actions"
|
msgid "Actions"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -4167,19 +4179,19 @@ msgstr ""
|
|||||||
msgid "This option must be selected"
|
msgid "This option must be selected"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: part/api.py:1073
|
#: part/api.py:1074
|
||||||
msgid "Must be greater than zero"
|
msgid "Must be greater than zero"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: part/api.py:1077
|
#: part/api.py:1078
|
||||||
msgid "Must be a valid quantity"
|
msgid "Must be a valid quantity"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: part/api.py:1092
|
#: part/api.py:1093
|
||||||
msgid "Specify location for initial part stock"
|
msgid "Specify location for initial part stock"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: part/api.py:1123 part/api.py:1127 part/api.py:1142 part/api.py:1146
|
#: part/api.py:1124 part/api.py:1128 part/api.py:1143 part/api.py:1147
|
||||||
msgid "This field is required"
|
msgid "This field is required"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -5773,8 +5785,8 @@ msgstr ""
|
|||||||
|
|
||||||
#: report/templates/report/inventree_test_report_base.html:79
|
#: report/templates/report/inventree_test_report_base.html:79
|
||||||
#: stock/models.py:641 stock/templates/stock/item_base.html:322
|
#: stock/models.py:641 stock/templates/stock/item_base.html:322
|
||||||
#: templates/js/translated/build.js:420 templates/js/translated/build.js:572
|
#: templates/js/translated/build.js:421 templates/js/translated/build.js:573
|
||||||
#: templates/js/translated/build.js:1173 templates/js/translated/build.js:1670
|
#: templates/js/translated/build.js:1174 templates/js/translated/build.js:1671
|
||||||
#: templates/js/translated/model_renderers.js:118
|
#: templates/js/translated/model_renderers.js:118
|
||||||
#: templates/js/translated/order.js:115 templates/js/translated/order.js:3240
|
#: templates/js/translated/order.js:115 templates/js/translated/order.js:3240
|
||||||
#: templates/js/translated/order.js:3329 templates/js/translated/stock.js:486
|
#: templates/js/translated/order.js:3329 templates/js/translated/stock.js:486
|
||||||
@@ -6395,7 +6407,7 @@ msgid "Available Quantity"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: stock/templates/stock/item_base.html:394
|
#: stock/templates/stock/item_base.html:394
|
||||||
#: templates/js/translated/build.js:1692
|
#: templates/js/translated/build.js:1693
|
||||||
msgid "No location set"
|
msgid "No location set"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -6808,7 +6820,7 @@ msgid "Plugin Settings"
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/InvenTree/settings/plugin.html:16
|
#: templates/InvenTree/settings/plugin.html:16
|
||||||
msgid "Changing the settings below require you to immediatly restart the server. Do not change this while under active usage."
|
msgid "Changing the settings below require you to immediately restart the server. Do not change this while under active usage."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/InvenTree/settings/plugin.html:34
|
#: templates/InvenTree/settings/plugin.html:34
|
||||||
@@ -7689,19 +7701,19 @@ msgstr ""
|
|||||||
msgid "No attachments found"
|
msgid "No attachments found"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/attachment.js:218
|
#: templates/js/translated/attachment.js:219
|
||||||
msgid "Edit Attachment"
|
msgid "Edit Attachment"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/attachment.js:287
|
#: templates/js/translated/attachment.js:289
|
||||||
msgid "Upload Date"
|
msgid "Upload Date"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/attachment.js:310
|
#: templates/js/translated/attachment.js:312
|
||||||
msgid "Edit attachment"
|
msgid "Edit attachment"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/attachment.js:319
|
#: templates/js/translated/attachment.js:321
|
||||||
msgid "Delete attachment"
|
msgid "Delete attachment"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -7921,25 +7933,25 @@ msgstr ""
|
|||||||
msgid "Substitutes Available"
|
msgid "Substitutes Available"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/bom.js:832 templates/js/translated/build.js:1768
|
#: templates/js/translated/bom.js:832 templates/js/translated/build.js:1769
|
||||||
msgid "Variant stock allowed"
|
msgid "Variant stock allowed"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/bom.js:900 templates/js/translated/build.js:1813
|
#: templates/js/translated/bom.js:900 templates/js/translated/build.js:1814
|
||||||
#: templates/js/translated/order.js:3577
|
#: templates/js/translated/order.js:3577
|
||||||
msgid "No Stock Available"
|
msgid "No Stock Available"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/bom.js:904 templates/js/translated/build.js:1817
|
#: templates/js/translated/bom.js:904 templates/js/translated/build.js:1818
|
||||||
msgid "Includes variant and substitute stock"
|
msgid "Includes variant and substitute stock"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/bom.js:906 templates/js/translated/build.js:1819
|
#: templates/js/translated/bom.js:906 templates/js/translated/build.js:1820
|
||||||
#: templates/js/translated/part.js:759
|
#: templates/js/translated/part.js:759
|
||||||
msgid "Includes variant stock"
|
msgid "Includes variant stock"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/bom.js:908 templates/js/translated/build.js:1821
|
#: templates/js/translated/bom.js:908 templates/js/translated/build.js:1822
|
||||||
msgid "Includes substitute stock"
|
msgid "Includes substitute stock"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -7979,11 +7991,11 @@ msgstr ""
|
|||||||
msgid "Delete BOM Item"
|
msgid "Delete BOM Item"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/bom.js:1158 templates/js/translated/build.js:1614
|
#: templates/js/translated/bom.js:1158 templates/js/translated/build.js:1615
|
||||||
msgid "No BOM items found"
|
msgid "No BOM items found"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/bom.js:1402 templates/js/translated/build.js:1752
|
#: templates/js/translated/bom.js:1402 templates/js/translated/build.js:1753
|
||||||
msgid "Required Part"
|
msgid "Required Part"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -8015,256 +8027,256 @@ msgstr ""
|
|||||||
msgid "There are incomplete outputs remaining for this build order"
|
msgid "There are incomplete outputs remaining for this build order"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:185
|
#: templates/js/translated/build.js:186
|
||||||
msgid "Build order is ready to be completed"
|
msgid "Build order is ready to be completed"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:190
|
#: templates/js/translated/build.js:191
|
||||||
msgid "Build Order is incomplete"
|
msgid "Build Order is incomplete"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:218
|
#: templates/js/translated/build.js:219
|
||||||
msgid "Complete Build Order"
|
msgid "Complete Build Order"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:259 templates/js/translated/stock.js:92
|
#: templates/js/translated/build.js:260 templates/js/translated/stock.js:92
|
||||||
#: templates/js/translated/stock.js:210
|
#: templates/js/translated/stock.js:210
|
||||||
msgid "Next available serial number"
|
msgid "Next available serial number"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:261 templates/js/translated/stock.js:94
|
#: templates/js/translated/build.js:262 templates/js/translated/stock.js:94
|
||||||
#: templates/js/translated/stock.js:212
|
#: templates/js/translated/stock.js:212
|
||||||
msgid "Latest serial number"
|
msgid "Latest serial number"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:270
|
#: templates/js/translated/build.js:271
|
||||||
msgid "The Bill of Materials contains trackable parts"
|
msgid "The Bill of Materials contains trackable parts"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:271
|
#: templates/js/translated/build.js:272
|
||||||
msgid "Build outputs must be generated individually"
|
msgid "Build outputs must be generated individually"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:279
|
#: templates/js/translated/build.js:280
|
||||||
msgid "Trackable parts can have serial numbers specified"
|
msgid "Trackable parts can have serial numbers specified"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:280
|
#: templates/js/translated/build.js:281
|
||||||
msgid "Enter serial numbers to generate multiple single build outputs"
|
msgid "Enter serial numbers to generate multiple single build outputs"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:287
|
#: templates/js/translated/build.js:288
|
||||||
msgid "Create Build Output"
|
msgid "Create Build Output"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:318
|
#: templates/js/translated/build.js:319
|
||||||
msgid "Allocate stock items to this build output"
|
msgid "Allocate stock items to this build output"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:329
|
#: templates/js/translated/build.js:330
|
||||||
msgid "Unallocate stock from build output"
|
msgid "Unallocate stock from build output"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:338
|
#: templates/js/translated/build.js:339
|
||||||
msgid "Complete build output"
|
msgid "Complete build output"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:346
|
#: templates/js/translated/build.js:347
|
||||||
msgid "Delete build output"
|
msgid "Delete build output"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:369
|
#: templates/js/translated/build.js:370
|
||||||
msgid "Are you sure you wish to unallocate stock items from this build?"
|
msgid "Are you sure you wish to unallocate stock items from this build?"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:387
|
#: templates/js/translated/build.js:388
|
||||||
msgid "Unallocate Stock Items"
|
msgid "Unallocate Stock Items"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:407 templates/js/translated/build.js:559
|
#: templates/js/translated/build.js:408 templates/js/translated/build.js:560
|
||||||
msgid "Select Build Outputs"
|
msgid "Select Build Outputs"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:408 templates/js/translated/build.js:560
|
#: templates/js/translated/build.js:409 templates/js/translated/build.js:561
|
||||||
msgid "At least one build output must be selected"
|
msgid "At least one build output must be selected"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:462 templates/js/translated/build.js:614
|
#: templates/js/translated/build.js:463 templates/js/translated/build.js:615
|
||||||
msgid "Output"
|
msgid "Output"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:480
|
#: templates/js/translated/build.js:481
|
||||||
msgid "Complete Build Outputs"
|
msgid "Complete Build Outputs"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:627
|
#: templates/js/translated/build.js:628
|
||||||
msgid "Delete Build Outputs"
|
msgid "Delete Build Outputs"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:716
|
#: templates/js/translated/build.js:717
|
||||||
msgid "No build order allocations found"
|
msgid "No build order allocations found"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:754
|
#: templates/js/translated/build.js:755
|
||||||
msgid "Location not specified"
|
msgid "Location not specified"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:1133
|
#: templates/js/translated/build.js:1134
|
||||||
msgid "No active build outputs found"
|
msgid "No active build outputs found"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:1202
|
#: templates/js/translated/build.js:1203
|
||||||
msgid "Allocated Stock"
|
msgid "Allocated Stock"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:1209
|
#: templates/js/translated/build.js:1210
|
||||||
msgid "No tracked BOM items for this build"
|
msgid "No tracked BOM items for this build"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:1231
|
#: templates/js/translated/build.js:1232
|
||||||
msgid "Completed Tests"
|
msgid "Completed Tests"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:1236
|
#: templates/js/translated/build.js:1237
|
||||||
msgid "No required tests for this build"
|
msgid "No required tests for this build"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:1709 templates/js/translated/build.js:2660
|
#: templates/js/translated/build.js:1710 templates/js/translated/build.js:2661
|
||||||
#: templates/js/translated/order.js:3277
|
#: templates/js/translated/order.js:3277
|
||||||
msgid "Edit stock allocation"
|
msgid "Edit stock allocation"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:1711 templates/js/translated/build.js:2661
|
#: templates/js/translated/build.js:1712 templates/js/translated/build.js:2662
|
||||||
#: templates/js/translated/order.js:3278
|
#: templates/js/translated/order.js:3278
|
||||||
msgid "Delete stock allocation"
|
msgid "Delete stock allocation"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:1729
|
#: templates/js/translated/build.js:1730
|
||||||
msgid "Edit Allocation"
|
msgid "Edit Allocation"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:1739
|
#: templates/js/translated/build.js:1740
|
||||||
msgid "Remove Allocation"
|
msgid "Remove Allocation"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:1764
|
#: templates/js/translated/build.js:1765
|
||||||
msgid "Substitute parts available"
|
msgid "Substitute parts available"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:1781
|
#: templates/js/translated/build.js:1782
|
||||||
msgid "Quantity Per"
|
msgid "Quantity Per"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:1807 templates/js/translated/order.js:3584
|
#: templates/js/translated/build.js:1808 templates/js/translated/order.js:3584
|
||||||
msgid "Insufficient stock available"
|
msgid "Insufficient stock available"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:1809 templates/js/translated/order.js:3582
|
#: templates/js/translated/build.js:1810 templates/js/translated/order.js:3582
|
||||||
msgid "Sufficient stock available"
|
msgid "Sufficient stock available"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:1838 templates/js/translated/build.js:2083
|
#: templates/js/translated/build.js:1839 templates/js/translated/build.js:2084
|
||||||
#: templates/js/translated/build.js:2656 templates/js/translated/order.js:3596
|
#: templates/js/translated/build.js:2657 templates/js/translated/order.js:3596
|
||||||
msgid "Allocated"
|
msgid "Allocated"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:1886 templates/js/translated/order.js:3676
|
#: templates/js/translated/build.js:1887 templates/js/translated/order.js:3676
|
||||||
msgid "Build stock"
|
msgid "Build stock"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:1890 templates/stock_table.html:50
|
#: templates/js/translated/build.js:1891 templates/stock_table.html:50
|
||||||
msgid "Order stock"
|
msgid "Order stock"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:1893 templates/js/translated/order.js:3669
|
#: templates/js/translated/build.js:1894 templates/js/translated/order.js:3669
|
||||||
msgid "Allocate stock"
|
msgid "Allocate stock"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:1932 templates/js/translated/label.js:172
|
#: templates/js/translated/build.js:1933 templates/js/translated/label.js:172
|
||||||
#: templates/js/translated/order.js:756 templates/js/translated/order.js:2804
|
#: templates/js/translated/order.js:756 templates/js/translated/order.js:2804
|
||||||
#: templates/js/translated/report.js:225
|
#: templates/js/translated/report.js:225
|
||||||
msgid "Select Parts"
|
msgid "Select Parts"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:1933 templates/js/translated/order.js:2805
|
#: templates/js/translated/build.js:1934 templates/js/translated/order.js:2805
|
||||||
msgid "You must select at least one part to allocate"
|
msgid "You must select at least one part to allocate"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:1982 templates/js/translated/order.js:2753
|
#: templates/js/translated/build.js:1983 templates/js/translated/order.js:2753
|
||||||
msgid "Specify stock allocation quantity"
|
msgid "Specify stock allocation quantity"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:2056
|
#: templates/js/translated/build.js:2057
|
||||||
msgid "All Parts Allocated"
|
msgid "All Parts Allocated"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:2057
|
#: templates/js/translated/build.js:2058
|
||||||
msgid "All selected parts have been fully allocated"
|
msgid "All selected parts have been fully allocated"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:2071 templates/js/translated/order.js:2819
|
#: templates/js/translated/build.js:2072 templates/js/translated/order.js:2819
|
||||||
msgid "Select source location (leave blank to take from all locations)"
|
msgid "Select source location (leave blank to take from all locations)"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:2099
|
#: templates/js/translated/build.js:2100
|
||||||
msgid "Allocate Stock Items to Build Order"
|
msgid "Allocate Stock Items to Build Order"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:2110 templates/js/translated/order.js:2916
|
#: templates/js/translated/build.js:2111 templates/js/translated/order.js:2916
|
||||||
msgid "No matching stock locations"
|
msgid "No matching stock locations"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:2182 templates/js/translated/order.js:2993
|
#: templates/js/translated/build.js:2183 templates/js/translated/order.js:2993
|
||||||
msgid "No matching stock items"
|
msgid "No matching stock items"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:2279
|
#: templates/js/translated/build.js:2280
|
||||||
msgid "Automatic Stock Allocation"
|
msgid "Automatic Stock Allocation"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:2280
|
#: templates/js/translated/build.js:2281
|
||||||
msgid "Stock items will be automatically allocated to this build order, according to the provided guidelines"
|
msgid "Stock items will be automatically allocated to this build order, according to the provided guidelines"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:2282
|
#: templates/js/translated/build.js:2283
|
||||||
msgid "If a location is specifed, stock will only be allocated from that location"
|
msgid "If a location is specifed, stock will only be allocated from that location"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:2283
|
#: templates/js/translated/build.js:2284
|
||||||
msgid "If stock is considered interchangeable, it will be allocated from the first location it is found"
|
msgid "If stock is considered interchangeable, it will be allocated from the first location it is found"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:2284
|
#: templates/js/translated/build.js:2285
|
||||||
msgid "If substitute stock is allowed, it will be used where stock of the primary part cannot be found"
|
msgid "If substitute stock is allowed, it will be used where stock of the primary part cannot be found"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:2305
|
#: templates/js/translated/build.js:2306
|
||||||
msgid "Allocate Stock Items"
|
msgid "Allocate Stock Items"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:2412
|
#: templates/js/translated/build.js:2413
|
||||||
msgid "No builds matching query"
|
msgid "No builds matching query"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:2447 templates/js/translated/part.js:1383
|
#: templates/js/translated/build.js:2448 templates/js/translated/part.js:1383
|
||||||
#: templates/js/translated/part.js:1850 templates/js/translated/stock.js:1682
|
#: templates/js/translated/part.js:1850 templates/js/translated/stock.js:1682
|
||||||
#: templates/js/translated/stock.js:2340
|
#: templates/js/translated/stock.js:2340
|
||||||
msgid "Select"
|
msgid "Select"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:2467
|
#: templates/js/translated/build.js:2468
|
||||||
msgid "Build order is overdue"
|
msgid "Build order is overdue"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:2495
|
#: templates/js/translated/build.js:2496
|
||||||
msgid "Progress"
|
msgid "Progress"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:2531 templates/js/translated/stock.js:2582
|
#: templates/js/translated/build.js:2532 templates/js/translated/stock.js:2582
|
||||||
msgid "No user information"
|
msgid "No user information"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/build.js:2637
|
#: templates/js/translated/build.js:2638
|
||||||
msgid "No parts allocated for"
|
msgid "No parts allocated for"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
@@ -10058,61 +10070,61 @@ msgstr ""
|
|||||||
msgid "Select File Format"
|
msgid "Select File Format"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/tables.js:534
|
#: templates/js/translated/tables.js:535
|
||||||
msgid "Loading data"
|
msgid "Loading data"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/tables.js:537
|
#: templates/js/translated/tables.js:538
|
||||||
msgid "rows per page"
|
msgid "rows per page"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/tables.js:542
|
#: templates/js/translated/tables.js:543
|
||||||
msgid "Showing all rows"
|
msgid "Showing all rows"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/tables.js:544
|
#: templates/js/translated/tables.js:545
|
||||||
msgid "Showing"
|
msgid "Showing"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/tables.js:544
|
#: templates/js/translated/tables.js:545
|
||||||
msgid "to"
|
msgid "to"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/tables.js:544
|
#: templates/js/translated/tables.js:545
|
||||||
msgid "of"
|
msgid "of"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/tables.js:544
|
#: templates/js/translated/tables.js:545
|
||||||
msgid "rows"
|
msgid "rows"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/tables.js:548 templates/navbar.html:102
|
#: templates/js/translated/tables.js:549 templates/navbar.html:102
|
||||||
#: templates/search.html:8 templates/search_form.html:6
|
#: templates/search.html:8 templates/search_form.html:6
|
||||||
#: templates/search_form.html:7
|
#: templates/search_form.html:7
|
||||||
msgid "Search"
|
msgid "Search"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/tables.js:551
|
#: templates/js/translated/tables.js:552
|
||||||
msgid "No matching results"
|
msgid "No matching results"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/tables.js:554
|
#: templates/js/translated/tables.js:555
|
||||||
msgid "Hide/Show pagination"
|
msgid "Hide/Show pagination"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/tables.js:557
|
#: templates/js/translated/tables.js:558
|
||||||
msgid "Refresh"
|
msgid "Refresh"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/tables.js:560
|
#: templates/js/translated/tables.js:561
|
||||||
msgid "Toggle"
|
msgid "Toggle"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/tables.js:563
|
#: templates/js/translated/tables.js:564
|
||||||
msgid "Columns"
|
msgid "Columns"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: templates/js/translated/tables.js:566
|
#: templates/js/translated/tables.js:567
|
||||||
msgid "All"
|
msgid "All"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -4,7 +4,7 @@
|
|||||||
- model: order.purchaseorder
|
- model: order.purchaseorder
|
||||||
pk: 1
|
pk: 1
|
||||||
fields:
|
fields:
|
||||||
reference: '0001'
|
reference: 'PO-0001'
|
||||||
description: "Ordering some screws"
|
description: "Ordering some screws"
|
||||||
supplier: 1
|
supplier: 1
|
||||||
status: 10 # Pending
|
status: 10 # Pending
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
- model: order.purchaseorder
|
- model: order.purchaseorder
|
||||||
pk: 2
|
pk: 2
|
||||||
fields:
|
fields:
|
||||||
reference: '0002'
|
reference: 'PO-0002'
|
||||||
description: "Ordering some more screws"
|
description: "Ordering some more screws"
|
||||||
supplier: 3
|
supplier: 3
|
||||||
status: 10 # Pending
|
status: 10 # Pending
|
||||||
@@ -21,7 +21,7 @@
|
|||||||
- model: order.purchaseorder
|
- model: order.purchaseorder
|
||||||
pk: 3
|
pk: 3
|
||||||
fields:
|
fields:
|
||||||
reference: '0003'
|
reference: 'PO-0003'
|
||||||
description: 'Another PO'
|
description: 'Another PO'
|
||||||
supplier: 3
|
supplier: 3
|
||||||
status: 20 # Placed
|
status: 20 # Placed
|
||||||
@@ -29,7 +29,7 @@
|
|||||||
- model: order.purchaseorder
|
- model: order.purchaseorder
|
||||||
pk: 4
|
pk: 4
|
||||||
fields:
|
fields:
|
||||||
reference: '0004'
|
reference: 'PO-0004'
|
||||||
description: 'Another PO'
|
description: 'Another PO'
|
||||||
supplier: 3
|
supplier: 3
|
||||||
status: 20 # Placed
|
status: 20 # Placed
|
||||||
@@ -37,7 +37,7 @@
|
|||||||
- model: order.purchaseorder
|
- model: order.purchaseorder
|
||||||
pk: 5
|
pk: 5
|
||||||
fields:
|
fields:
|
||||||
reference: '0005'
|
reference: 'PO-0005'
|
||||||
description: 'Another PO'
|
description: 'Another PO'
|
||||||
supplier: 3
|
supplier: 3
|
||||||
status: 30 # Complete
|
status: 30 # Complete
|
||||||
@@ -45,7 +45,7 @@
|
|||||||
- model: order.purchaseorder
|
- model: order.purchaseorder
|
||||||
pk: 6
|
pk: 6
|
||||||
fields:
|
fields:
|
||||||
reference: '0006'
|
reference: 'PO-0006'
|
||||||
description: 'Another PO'
|
description: 'Another PO'
|
||||||
supplier: 3
|
supplier: 3
|
||||||
status: 40 # Cancelled
|
status: 40 # Cancelled
|
||||||
@@ -54,7 +54,7 @@
|
|||||||
- model: order.purchaseorder
|
- model: order.purchaseorder
|
||||||
pk: 7
|
pk: 7
|
||||||
fields:
|
fields:
|
||||||
reference: '0007'
|
reference: 'PO-0007'
|
||||||
description: 'Another PO'
|
description: 'Another PO'
|
||||||
supplier: 2
|
supplier: 2
|
||||||
status: 10 # Pending
|
status: 10 # Pending
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
# Generated by Django 3.2.4 on 2021-07-02 13:21
|
# Generated by Django 3.2.4 on 2021-07-02 13:21
|
||||||
|
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
import order.models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
@@ -14,11 +13,11 @@ class Migration(migrations.Migration):
|
|||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='purchaseorder',
|
model_name='purchaseorder',
|
||||||
name='reference',
|
name='reference',
|
||||||
field=models.CharField(default=order.models.get_next_po_number, help_text='Order reference', max_length=64, unique=True, verbose_name='Reference'),
|
field=models.CharField(default="PO", help_text='Order reference', max_length=64, unique=True, verbose_name='Reference'),
|
||||||
),
|
),
|
||||||
migrations.AlterField(
|
migrations.AlterField(
|
||||||
model_name='salesorder',
|
model_name='salesorder',
|
||||||
name='reference',
|
name='reference',
|
||||||
field=models.CharField(default=order.models.get_next_so_number, help_text='Order reference', max_length=64, unique=True, verbose_name='Reference'),
|
field=models.CharField(default="SO", help_text='Order reference', max_length=64, unique=True, verbose_name='Reference'),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
# Generated by Django 3.2.14 on 2022-07-07 11:55
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import order.validators
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('order', '0071_auto_20220628_0133'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='salesorder',
|
||||||
|
name='reference',
|
||||||
|
field=models.CharField(default=order.validators.generate_next_sales_order_reference, help_text='Order reference', max_length=64, unique=True, validators=[order.validators.validate_sales_order_reference], verbose_name='Reference'),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
# Generated by Django 3.2.14 on 2022-07-09 01:01
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import order.validators
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('order', '0072_alter_salesorder_reference'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='purchaseorder',
|
||||||
|
name='reference',
|
||||||
|
field=models.CharField(default=order.validators.generate_next_purchase_order_reference, help_text='Order reference', max_length=64, unique=True, validators=[order.validators.validate_purchase_order_reference], verbose_name='Reference'),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -0,0 +1,107 @@
|
|||||||
|
# Generated by Django 3.2.14 on 2022-07-09 01:08
|
||||||
|
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
def update_order_references(order_model, prefix):
|
||||||
|
"""Update all references of the given model, with the specified prefix"""
|
||||||
|
|
||||||
|
n = 0
|
||||||
|
|
||||||
|
for order in order_model.objects.all():
|
||||||
|
if not order.reference.startswith(prefix):
|
||||||
|
order.reference = prefix + order.reference
|
||||||
|
order.save()
|
||||||
|
|
||||||
|
n += 1
|
||||||
|
|
||||||
|
return n
|
||||||
|
|
||||||
|
|
||||||
|
def update_salesorder_reference(apps, schema_editor):
|
||||||
|
"""Migrate the reference pattern for the SalesOrder model"""
|
||||||
|
|
||||||
|
# Extract the existing "prefix" value
|
||||||
|
InvenTreeSetting = apps.get_model('common', 'inventreesetting')
|
||||||
|
|
||||||
|
try:
|
||||||
|
prefix = InvenTreeSetting.objects.get(key='SALESORDER_REFERENCE_PREFIX').value
|
||||||
|
except Exception:
|
||||||
|
prefix = 'SO-'
|
||||||
|
|
||||||
|
# Construct a reference pattern
|
||||||
|
pattern = prefix + '{ref:04d}'
|
||||||
|
|
||||||
|
# Create or update the BuildOrder.reference pattern
|
||||||
|
try:
|
||||||
|
setting = InvenTreeSetting.objects.get(key='SALESORDER_REFERENCE_PATTERN')
|
||||||
|
setting.value = pattern
|
||||||
|
setting.save()
|
||||||
|
except InvenTreeSetting.DoesNotExist:
|
||||||
|
setting = InvenTreeSetting.objects.create(
|
||||||
|
key='SALESORDER_REFERENCE_PATTERN',
|
||||||
|
value=pattern,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Update any existing sales order references
|
||||||
|
SalesOrder = apps.get_model('order', 'salesorder')
|
||||||
|
n = update_order_references(SalesOrder, prefix)
|
||||||
|
|
||||||
|
if n > 0:
|
||||||
|
print(f"Updated reference field for {n} SalesOrder objects")
|
||||||
|
|
||||||
|
|
||||||
|
def update_purchaseorder_reference(apps, schema_editor):
|
||||||
|
"""Migrate the reference pattern for the PurchaseOrder model"""
|
||||||
|
|
||||||
|
# Extract the existing "prefix" value
|
||||||
|
InvenTreeSetting = apps.get_model('common', 'inventreesetting')
|
||||||
|
|
||||||
|
try:
|
||||||
|
prefix = InvenTreeSetting.objects.get(key='PURCHASEORDER_REFERENCE_PREFIX').value
|
||||||
|
except Exception:
|
||||||
|
prefix = 'PO-'
|
||||||
|
|
||||||
|
# Construct a reference pattern
|
||||||
|
pattern = prefix + '{ref:04d}'
|
||||||
|
|
||||||
|
# Create or update the BuildOrder.reference pattern
|
||||||
|
try:
|
||||||
|
setting = InvenTreeSetting.objects.get(key='PURCHASEORDER_REFERENCE_PATTERN')
|
||||||
|
setting.value = pattern
|
||||||
|
setting.save()
|
||||||
|
except InvenTreeSetting.DoesNotExist:
|
||||||
|
setting = InvenTreeSetting.objects.create(
|
||||||
|
key='PURCHASEORDER_REFERENCE_PATTERN',
|
||||||
|
value=pattern,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Update any existing sales order references
|
||||||
|
PurchaseOrder = apps.get_model('order', 'purchaseorder')
|
||||||
|
n = update_order_references(PurchaseOrder, prefix)
|
||||||
|
|
||||||
|
if n > 0:
|
||||||
|
print(f"Updated reference field for {n} PurchaseOrder objects")
|
||||||
|
|
||||||
|
|
||||||
|
def nop(apps, schema_editor):
|
||||||
|
"""Empty function for reverse migration"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('order', '0073_alter_purchaseorder_reference'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RunPython(
|
||||||
|
update_salesorder_reference,
|
||||||
|
reverse_code=nop,
|
||||||
|
),
|
||||||
|
migrations.RunPython(
|
||||||
|
update_purchaseorder_reference,
|
||||||
|
reverse_code=nop,
|
||||||
|
)
|
||||||
|
]
|
||||||
+39
-61
@@ -24,14 +24,14 @@ from mptt.models import TreeForeignKey
|
|||||||
|
|
||||||
import InvenTree.helpers
|
import InvenTree.helpers
|
||||||
import InvenTree.ready
|
import InvenTree.ready
|
||||||
|
import order.validators
|
||||||
from common.notifications import InvenTreeNotificationBodies
|
from common.notifications import InvenTreeNotificationBodies
|
||||||
from common.settings import currency_code_default
|
from common.settings import currency_code_default
|
||||||
from company.models import Company, SupplierPart
|
from company.models import Company, SupplierPart
|
||||||
from InvenTree.exceptions import log_error
|
from InvenTree.exceptions import log_error
|
||||||
from InvenTree.fields import (InvenTreeModelMoneyField, InvenTreeNotesField,
|
from InvenTree.fields import (InvenTreeModelMoneyField, InvenTreeNotesField,
|
||||||
RoundingDecimalField)
|
RoundingDecimalField)
|
||||||
from InvenTree.helpers import (decimal2string, getSetting, increment,
|
from InvenTree.helpers import decimal2string, getSetting, notify_responsible
|
||||||
notify_responsible)
|
|
||||||
from InvenTree.models import InvenTreeAttachment, ReferenceIndexingMixin
|
from InvenTree.models import InvenTreeAttachment, ReferenceIndexingMixin
|
||||||
from InvenTree.status_codes import (PurchaseOrderStatus, SalesOrderStatus,
|
from InvenTree.status_codes import (PurchaseOrderStatus, SalesOrderStatus,
|
||||||
StockHistoryCode, StockStatus)
|
StockHistoryCode, StockStatus)
|
||||||
@@ -44,58 +44,6 @@ from users import models as UserModels
|
|||||||
logger = logging.getLogger('inventree')
|
logger = logging.getLogger('inventree')
|
||||||
|
|
||||||
|
|
||||||
def get_next_po_number():
|
|
||||||
"""Returns the next available PurchaseOrder reference number."""
|
|
||||||
if PurchaseOrder.objects.count() == 0:
|
|
||||||
return '0001'
|
|
||||||
|
|
||||||
order = PurchaseOrder.objects.exclude(reference=None).last()
|
|
||||||
|
|
||||||
attempts = {order.reference}
|
|
||||||
|
|
||||||
reference = order.reference
|
|
||||||
|
|
||||||
while 1:
|
|
||||||
reference = increment(reference)
|
|
||||||
|
|
||||||
if reference in attempts:
|
|
||||||
# Escape infinite recursion
|
|
||||||
return reference
|
|
||||||
|
|
||||||
if PurchaseOrder.objects.filter(reference=reference).exists():
|
|
||||||
attempts.add(reference)
|
|
||||||
else:
|
|
||||||
break
|
|
||||||
|
|
||||||
return reference
|
|
||||||
|
|
||||||
|
|
||||||
def get_next_so_number():
|
|
||||||
"""Returns the next available SalesOrder reference number."""
|
|
||||||
if SalesOrder.objects.count() == 0:
|
|
||||||
return '0001'
|
|
||||||
|
|
||||||
order = SalesOrder.objects.exclude(reference=None).last()
|
|
||||||
|
|
||||||
attempts = {order.reference}
|
|
||||||
|
|
||||||
reference = order.reference
|
|
||||||
|
|
||||||
while 1:
|
|
||||||
reference = increment(reference)
|
|
||||||
|
|
||||||
if reference in attempts:
|
|
||||||
# Escape infinite recursion
|
|
||||||
return reference
|
|
||||||
|
|
||||||
if SalesOrder.objects.filter(reference=reference).exists():
|
|
||||||
attempts.add(reference)
|
|
||||||
else:
|
|
||||||
break
|
|
||||||
|
|
||||||
return reference
|
|
||||||
|
|
||||||
|
|
||||||
class Order(MetadataMixin, ReferenceIndexingMixin):
|
class Order(MetadataMixin, ReferenceIndexingMixin):
|
||||||
"""Abstract model for an order.
|
"""Abstract model for an order.
|
||||||
|
|
||||||
@@ -119,7 +67,7 @@ class Order(MetadataMixin, ReferenceIndexingMixin):
|
|||||||
|
|
||||||
Ensures that the reference field is rebuilt whenever the instance is saved.
|
Ensures that the reference field is rebuilt whenever the instance is saved.
|
||||||
"""
|
"""
|
||||||
self.rebuild_reference_field()
|
self.reference_int = self.rebuild_reference_field(self.reference)
|
||||||
|
|
||||||
if not self.creation_date:
|
if not self.creation_date:
|
||||||
self.creation_date = datetime.now().date()
|
self.creation_date = datetime.now().date()
|
||||||
@@ -230,8 +178,21 @@ class PurchaseOrder(Order):
|
|||||||
"""Return the API URL associated with the PurchaseOrder model"""
|
"""Return the API URL associated with the PurchaseOrder model"""
|
||||||
return reverse('api-po-list')
|
return reverse('api-po-list')
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def api_defaults(cls, request):
|
||||||
|
"""Return default values for thsi model when issuing an API OPTIONS request"""
|
||||||
|
|
||||||
|
defaults = {
|
||||||
|
'reference': order.validators.generate_next_purchase_order_reference(),
|
||||||
|
}
|
||||||
|
|
||||||
|
return defaults
|
||||||
|
|
||||||
OVERDUE_FILTER = Q(status__in=PurchaseOrderStatus.OPEN) & ~Q(target_date=None) & Q(target_date__lte=datetime.now().date())
|
OVERDUE_FILTER = Q(status__in=PurchaseOrderStatus.OPEN) & ~Q(target_date=None) & Q(target_date__lte=datetime.now().date())
|
||||||
|
|
||||||
|
# Global setting for specifying reference pattern
|
||||||
|
REFERENCE_PATTERN_SETTING = 'PURCHASEORDER_REFERENCE_PATTERN'
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def filterByDate(queryset, min_date, max_date):
|
def filterByDate(queryset, min_date, max_date):
|
||||||
"""Filter by 'minimum and maximum date range'.
|
"""Filter by 'minimum and maximum date range'.
|
||||||
@@ -269,9 +230,8 @@ class PurchaseOrder(Order):
|
|||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
"""Render a string representation of this PurchaseOrder"""
|
"""Render a string representation of this PurchaseOrder"""
|
||||||
prefix = getSetting('PURCHASEORDER_REFERENCE_PREFIX')
|
|
||||||
|
|
||||||
return f"{prefix}{self.reference} - {self.supplier.name if self.supplier else _('deleted')}"
|
return f"{self.reference} - {self.supplier.name if self.supplier else _('deleted')}"
|
||||||
|
|
||||||
reference = models.CharField(
|
reference = models.CharField(
|
||||||
unique=True,
|
unique=True,
|
||||||
@@ -279,7 +239,10 @@ class PurchaseOrder(Order):
|
|||||||
blank=False,
|
blank=False,
|
||||||
verbose_name=_('Reference'),
|
verbose_name=_('Reference'),
|
||||||
help_text=_('Order reference'),
|
help_text=_('Order reference'),
|
||||||
default=get_next_po_number,
|
default=order.validators.generate_next_purchase_order_reference,
|
||||||
|
validators=[
|
||||||
|
order.validators.validate_purchase_order_reference,
|
||||||
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
status = models.PositiveIntegerField(default=PurchaseOrderStatus.PENDING, choices=PurchaseOrderStatus.items(),
|
status = models.PositiveIntegerField(default=PurchaseOrderStatus.PENDING, choices=PurchaseOrderStatus.items(),
|
||||||
@@ -595,8 +558,20 @@ class SalesOrder(Order):
|
|||||||
"""Return the API URL associated with the SalesOrder model"""
|
"""Return the API URL associated with the SalesOrder model"""
|
||||||
return reverse('api-so-list')
|
return reverse('api-so-list')
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def api_defaults(cls, request):
|
||||||
|
"""Return default values for this model when issuing an API OPTIONS request"""
|
||||||
|
defaults = {
|
||||||
|
'reference': order.validators.generate_next_sales_order_reference(),
|
||||||
|
}
|
||||||
|
|
||||||
|
return defaults
|
||||||
|
|
||||||
OVERDUE_FILTER = Q(status__in=SalesOrderStatus.OPEN) & ~Q(target_date=None) & Q(target_date__lte=datetime.now().date())
|
OVERDUE_FILTER = Q(status__in=SalesOrderStatus.OPEN) & ~Q(target_date=None) & Q(target_date__lte=datetime.now().date())
|
||||||
|
|
||||||
|
# Global setting for specifying reference pattern
|
||||||
|
REFERENCE_PATTERN_SETTING = 'SALESORDER_REFERENCE_PATTERN'
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def filterByDate(queryset, min_date, max_date):
|
def filterByDate(queryset, min_date, max_date):
|
||||||
"""Filter by "minimum and maximum date range".
|
"""Filter by "minimum and maximum date range".
|
||||||
@@ -634,9 +609,8 @@ class SalesOrder(Order):
|
|||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
"""Render a string representation of this SalesOrder"""
|
"""Render a string representation of this SalesOrder"""
|
||||||
prefix = getSetting('SALESORDER_REFERENCE_PREFIX')
|
|
||||||
|
|
||||||
return f"{prefix}{self.reference} - {self.customer.name if self.customer else _('deleted')}"
|
return f"{self.reference} - {self.customer.name if self.customer else _('deleted')}"
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
"""Return the web URL for the detail view of this order"""
|
"""Return the web URL for the detail view of this order"""
|
||||||
@@ -648,7 +622,10 @@ class SalesOrder(Order):
|
|||||||
blank=False,
|
blank=False,
|
||||||
verbose_name=_('Reference'),
|
verbose_name=_('Reference'),
|
||||||
help_text=_('Order reference'),
|
help_text=_('Order reference'),
|
||||||
default=get_next_so_number,
|
default=order.validators.generate_next_sales_order_reference,
|
||||||
|
validators=[
|
||||||
|
order.validators.validate_sales_order_reference,
|
||||||
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
customer = models.ForeignKey(
|
customer = models.ForeignKey(
|
||||||
@@ -957,6 +934,7 @@ class OrderExtraLine(OrderLineItem):
|
|||||||
max_digits=19,
|
max_digits=19,
|
||||||
decimal_places=4,
|
decimal_places=4,
|
||||||
null=True, blank=True,
|
null=True, blank=True,
|
||||||
|
allow_negative=True,
|
||||||
verbose_name=_('Price'),
|
verbose_name=_('Price'),
|
||||||
help_text=_('Unit price'),
|
help_text=_('Unit price'),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -23,8 +23,7 @@ from InvenTree.helpers import extract_serial_numbers, normalize
|
|||||||
from InvenTree.serializers import (InvenTreeAttachmentSerializer,
|
from InvenTree.serializers import (InvenTreeAttachmentSerializer,
|
||||||
InvenTreeDecimalField,
|
InvenTreeDecimalField,
|
||||||
InvenTreeModelSerializer,
|
InvenTreeModelSerializer,
|
||||||
InvenTreeMoneySerializer,
|
InvenTreeMoneySerializer)
|
||||||
ReferenceIndexingSerializerMixin)
|
|
||||||
from InvenTree.status_codes import (PurchaseOrderStatus, SalesOrderStatus,
|
from InvenTree.status_codes import (PurchaseOrderStatus, SalesOrderStatus,
|
||||||
StockStatus)
|
StockStatus)
|
||||||
from part.serializers import PartBriefSerializer
|
from part.serializers import PartBriefSerializer
|
||||||
@@ -86,7 +85,7 @@ class AbstractExtraLineMeta:
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class PurchaseOrderSerializer(AbstractOrderSerializer, ReferenceIndexingSerializerMixin, InvenTreeModelSerializer):
|
class PurchaseOrderSerializer(AbstractOrderSerializer, InvenTreeModelSerializer):
|
||||||
"""Serializer for a PurchaseOrder object."""
|
"""Serializer for a PurchaseOrder object."""
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
@@ -130,6 +129,14 @@ class PurchaseOrderSerializer(AbstractOrderSerializer, ReferenceIndexingSerializ
|
|||||||
|
|
||||||
reference = serializers.CharField(required=True)
|
reference = serializers.CharField(required=True)
|
||||||
|
|
||||||
|
def validate_reference(self, reference):
|
||||||
|
"""Custom validation for the reference field"""
|
||||||
|
|
||||||
|
# Ensure that the reference matches the required pattern
|
||||||
|
order.models.PurchaseOrder.validate_reference_field(reference)
|
||||||
|
|
||||||
|
return reference
|
||||||
|
|
||||||
responsible_detail = OwnerSerializer(source='responsible', read_only=True, many=False)
|
responsible_detail = OwnerSerializer(source='responsible', read_only=True, many=False)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
@@ -639,7 +646,7 @@ class PurchaseOrderAttachmentSerializer(InvenTreeAttachmentSerializer):
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class SalesOrderSerializer(AbstractOrderSerializer, ReferenceIndexingSerializerMixin, InvenTreeModelSerializer):
|
class SalesOrderSerializer(AbstractOrderSerializer, InvenTreeModelSerializer):
|
||||||
"""Serializers for the SalesOrder object."""
|
"""Serializers for the SalesOrder object."""
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
@@ -683,6 +690,14 @@ class SalesOrderSerializer(AbstractOrderSerializer, ReferenceIndexingSerializerM
|
|||||||
|
|
||||||
reference = serializers.CharField(required=True)
|
reference = serializers.CharField(required=True)
|
||||||
|
|
||||||
|
def validate_reference(self, reference):
|
||||||
|
"""Custom validation for the reference field"""
|
||||||
|
|
||||||
|
# Ensure that the reference matches the required pattern
|
||||||
|
order.models.SalesOrder.validate_reference_field(reference)
|
||||||
|
|
||||||
|
return reference
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
"""Metaclass options."""
|
"""Metaclass options."""
|
||||||
|
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ src="{% static 'img/blank_image.png' %}"
|
|||||||
<tr>
|
<tr>
|
||||||
<td><span class='fas fa-hashtag'></span></td>
|
<td><span class='fas fa-hashtag'></span></td>
|
||||||
<td>{% trans "Order Reference" %}</td>
|
<td>{% trans "Order Reference" %}</td>
|
||||||
<td>{% settings_value 'PURCHASEORDER_REFERENCE_PREFIX' %}{{ order.reference }}{% include "clip.html"%}</td>
|
<td>{{ order.reference }}{% include "clip.html"%}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><span class='fas fa-info-circle'></span></td>
|
<td><span class='fas fa-info-circle'></span></td>
|
||||||
@@ -222,7 +222,7 @@ $("#edit-order").click(function() {
|
|||||||
constructForm('{% url "api-po-detail" order.pk %}', {
|
constructForm('{% url "api-po-detail" order.pk %}', {
|
||||||
fields: {
|
fields: {
|
||||||
reference: {
|
reference: {
|
||||||
prefix: global_settings.PURCHASEORDER_REFERENCE_PREFIX,
|
icon: 'fa-hashtag',
|
||||||
},
|
},
|
||||||
{% if order.lines.count == 0 and order.status == PurchaseOrderStatus.PENDING %}
|
{% if order.lines.count == 0 and order.status == PurchaseOrderStatus.PENDING %}
|
||||||
supplier: {
|
supplier: {
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ src="{% static 'img/blank_image.png' %}"
|
|||||||
<tr>
|
<tr>
|
||||||
<td><span class='fas fa-hashtag'></span></td>
|
<td><span class='fas fa-hashtag'></span></td>
|
||||||
<td>{% trans "Order Reference" %}</td>
|
<td>{% trans "Order Reference" %}</td>
|
||||||
<td>{% settings_value 'SALESORDER_REFERENCE_PREFIX' %}{{ order.reference }}{% include "clip.html"%}</td>
|
<td>{{ order.reference }}{% include "clip.html"%}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><span class='fas fa-info-circle'></span></td>
|
<td><span class='fas fa-info-circle'></span></td>
|
||||||
@@ -209,7 +209,7 @@ $("#edit-order").click(function() {
|
|||||||
constructForm('{% url "api-so-detail" order.pk %}', {
|
constructForm('{% url "api-so-detail" order.pk %}', {
|
||||||
fields: {
|
fields: {
|
||||||
reference: {
|
reference: {
|
||||||
prefix: global_settings.SALESORDER_REFERENCE_PREFIX,
|
icon: 'fa-hashtag',
|
||||||
},
|
},
|
||||||
{% if order.lines.count == 0 and order.status == SalesOrderStatus.PENDING %}
|
{% if order.lines.count == 0 and order.status == SalesOrderStatus.PENDING %}
|
||||||
customer: {
|
customer: {
|
||||||
|
|||||||
+46
-17
@@ -94,23 +94,28 @@ class PurchaseOrderTest(OrderTest):
|
|||||||
self.assertEqual(data['description'], 'Ordering some screws')
|
self.assertEqual(data['description'], 'Ordering some screws')
|
||||||
|
|
||||||
def test_po_reference(self):
|
def test_po_reference(self):
|
||||||
"""Test that a reference with a too big / small reference is not possible."""
|
"""Test that a reference with a too big / small reference is handled correctly."""
|
||||||
# get permissions
|
# get permissions
|
||||||
self.assignRole('purchase_order.add')
|
self.assignRole('purchase_order.add')
|
||||||
|
|
||||||
url = reverse('api-po-list')
|
url = reverse('api-po-list')
|
||||||
huge_number = 9223372036854775808
|
huge_number = "PO-92233720368547758089999999999999999"
|
||||||
|
|
||||||
self.post(
|
response = self.post(
|
||||||
url,
|
url,
|
||||||
{
|
{
|
||||||
'supplier': 1,
|
'supplier': 1,
|
||||||
'reference': huge_number,
|
'reference': huge_number,
|
||||||
'description': 'PO not created via the API',
|
'description': 'PO created via the API',
|
||||||
},
|
},
|
||||||
expected_code=201,
|
expected_code=201,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
order = models.PurchaseOrder.objects.get(pk=response.data['pk'])
|
||||||
|
|
||||||
|
self.assertEqual(order.reference, 'PO-92233720368547758089999999999999999')
|
||||||
|
self.assertEqual(order.reference_int, 0x7fffffff)
|
||||||
|
|
||||||
def test_po_attachments(self):
|
def test_po_attachments(self):
|
||||||
"""Test the list endpoint for the PurchaseOrderAttachment model"""
|
"""Test the list endpoint for the PurchaseOrderAttachment model"""
|
||||||
url = reverse('api-po-attachment-list')
|
url = reverse('api-po-attachment-list')
|
||||||
@@ -149,7 +154,7 @@ class PurchaseOrderTest(OrderTest):
|
|||||||
url,
|
url,
|
||||||
{
|
{
|
||||||
'supplier': 1,
|
'supplier': 1,
|
||||||
'reference': '123456789-xyz',
|
'reference': 'PO-123456789',
|
||||||
'description': 'PO created via the API',
|
'description': 'PO created via the API',
|
||||||
},
|
},
|
||||||
expected_code=201
|
expected_code=201
|
||||||
@@ -177,19 +182,19 @@ class PurchaseOrderTest(OrderTest):
|
|||||||
# Get detail info!
|
# Get detail info!
|
||||||
response = self.get(url)
|
response = self.get(url)
|
||||||
self.assertEqual(response.data['pk'], pk)
|
self.assertEqual(response.data['pk'], pk)
|
||||||
self.assertEqual(response.data['reference'], '123456789-xyz')
|
self.assertEqual(response.data['reference'], 'PO-123456789')
|
||||||
|
|
||||||
# Try to alter (edit) the PurchaseOrder
|
# Try to alter (edit) the PurchaseOrder
|
||||||
response = self.patch(
|
response = self.patch(
|
||||||
url,
|
url,
|
||||||
{
|
{
|
||||||
'reference': '12345-abc',
|
'reference': 'PO-12345',
|
||||||
},
|
},
|
||||||
expected_code=200
|
expected_code=200
|
||||||
)
|
)
|
||||||
|
|
||||||
# Reference should have changed
|
# Reference should have changed
|
||||||
self.assertEqual(response.data['reference'], '12345-abc')
|
self.assertEqual(response.data['reference'], 'PO-12345')
|
||||||
|
|
||||||
# Now, let's try to delete it!
|
# Now, let's try to delete it!
|
||||||
# Initially, we do *not* have the required permission!
|
# Initially, we do *not* have the required permission!
|
||||||
@@ -213,7 +218,7 @@ class PurchaseOrderTest(OrderTest):
|
|||||||
self.post(
|
self.post(
|
||||||
reverse('api-po-list'),
|
reverse('api-po-list'),
|
||||||
{
|
{
|
||||||
'reference': '12345678',
|
'reference': 'PO-12345678',
|
||||||
'supplier': 1,
|
'supplier': 1,
|
||||||
'description': 'A test purchase order',
|
'description': 'A test purchase order',
|
||||||
},
|
},
|
||||||
@@ -807,7 +812,7 @@ class SalesOrderTest(OrderTest):
|
|||||||
url,
|
url,
|
||||||
{
|
{
|
||||||
'customer': 4,
|
'customer': 4,
|
||||||
'reference': '12345',
|
'reference': 'SO-12345',
|
||||||
'description': 'Sales order',
|
'description': 'Sales order',
|
||||||
},
|
},
|
||||||
expected_code=201
|
expected_code=201
|
||||||
@@ -824,7 +829,7 @@ class SalesOrderTest(OrderTest):
|
|||||||
url,
|
url,
|
||||||
{
|
{
|
||||||
'customer': 4,
|
'customer': 4,
|
||||||
'reference': '12345',
|
'reference': 'SO-12345',
|
||||||
'description': 'Another sales order',
|
'description': 'Another sales order',
|
||||||
},
|
},
|
||||||
expected_code=400
|
expected_code=400
|
||||||
@@ -834,19 +839,28 @@ class SalesOrderTest(OrderTest):
|
|||||||
|
|
||||||
# Extract detail info for the SalesOrder
|
# Extract detail info for the SalesOrder
|
||||||
response = self.get(url)
|
response = self.get(url)
|
||||||
self.assertEqual(response.data['reference'], '12345')
|
self.assertEqual(response.data['reference'], 'SO-12345')
|
||||||
|
|
||||||
# Try to alter (edit) the SalesOrder
|
# Try to alter (edit) the SalesOrder
|
||||||
|
# Initially try with an invalid reference field value
|
||||||
response = self.patch(
|
response = self.patch(
|
||||||
url,
|
url,
|
||||||
{
|
{
|
||||||
'reference': '12345-a',
|
'reference': 'SO-12345-a',
|
||||||
|
},
|
||||||
|
expected_code=400
|
||||||
|
)
|
||||||
|
|
||||||
|
response = self.patch(
|
||||||
|
url,
|
||||||
|
{
|
||||||
|
'reference': 'SO-12346',
|
||||||
},
|
},
|
||||||
expected_code=200
|
expected_code=200
|
||||||
)
|
)
|
||||||
|
|
||||||
# Reference should have changed
|
# Reference should have changed
|
||||||
self.assertEqual(response.data['reference'], '12345-a')
|
self.assertEqual(response.data['reference'], 'SO-12346')
|
||||||
|
|
||||||
# Now, let's try to delete this SalesOrder
|
# Now, let's try to delete this SalesOrder
|
||||||
# Initially, we do not have the required permission
|
# Initially, we do not have the required permission
|
||||||
@@ -866,14 +880,29 @@ class SalesOrderTest(OrderTest):
|
|||||||
"""Test that we can create a new SalesOrder via the API."""
|
"""Test that we can create a new SalesOrder via the API."""
|
||||||
self.assignRole('sales_order.add')
|
self.assignRole('sales_order.add')
|
||||||
|
|
||||||
self.post(
|
url = reverse('api-so-list')
|
||||||
reverse('api-so-list'),
|
|
||||||
|
# Will fail due to invalid reference field
|
||||||
|
response = self.post(
|
||||||
|
url,
|
||||||
{
|
{
|
||||||
'reference': '1234566778',
|
'reference': '1234566778',
|
||||||
'customer': 4,
|
'customer': 4,
|
||||||
'description': 'A test sales order',
|
'description': 'A test sales order',
|
||||||
},
|
},
|
||||||
expected_code=201
|
expected_code=400,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertIn('Reference must match required pattern', str(response.data['reference']))
|
||||||
|
|
||||||
|
self.post(
|
||||||
|
url,
|
||||||
|
{
|
||||||
|
'reference': 'SO-12345',
|
||||||
|
'customer': 4,
|
||||||
|
'description': 'A better test sales order',
|
||||||
|
},
|
||||||
|
expected_code=201,
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_so_cancel(self):
|
def test_so_cancel(self):
|
||||||
|
|||||||
@@ -40,19 +40,27 @@ class SalesOrderTest(TestCase):
|
|||||||
# Create a SalesOrder to ship against
|
# Create a SalesOrder to ship against
|
||||||
self.order = SalesOrder.objects.create(
|
self.order = SalesOrder.objects.create(
|
||||||
customer=self.customer,
|
customer=self.customer,
|
||||||
reference='1234',
|
reference='SO-1234',
|
||||||
customer_reference='ABC 55555'
|
customer_reference='ABC 55555'
|
||||||
)
|
)
|
||||||
|
|
||||||
# Create a Shipment against this SalesOrder
|
# Create a Shipment against this SalesOrder
|
||||||
self.shipment = SalesOrderShipment.objects.create(
|
self.shipment = SalesOrderShipment.objects.create(
|
||||||
order=self.order,
|
order=self.order,
|
||||||
reference='001',
|
reference='SO-001',
|
||||||
)
|
)
|
||||||
|
|
||||||
# Create a line item
|
# Create a line item
|
||||||
self.line = SalesOrderLineItem.objects.create(quantity=50, order=self.order, part=self.part)
|
self.line = SalesOrderLineItem.objects.create(quantity=50, order=self.order, part=self.part)
|
||||||
|
|
||||||
|
def test_so_reference(self):
|
||||||
|
"""Unit tests for sales order generation"""
|
||||||
|
|
||||||
|
# Test that a good reference is created when we have no existing orders
|
||||||
|
SalesOrder.objects.all().delete()
|
||||||
|
|
||||||
|
self.assertEqual(SalesOrder.generate_reference(), 'SO-0001')
|
||||||
|
|
||||||
def test_rebuild_reference(self):
|
def test_rebuild_reference(self):
|
||||||
"""Test that the 'reference_int' field gets rebuilt when the model is saved"""
|
"""Test that the 'reference_int' field gets rebuilt when the model is saved"""
|
||||||
|
|
||||||
|
|||||||
@@ -35,15 +35,17 @@ class OrderTest(TestCase):
|
|||||||
|
|
||||||
def test_basics(self):
|
def test_basics(self):
|
||||||
"""Basic tests e.g. repr functions etc."""
|
"""Basic tests e.g. repr functions etc."""
|
||||||
order = PurchaseOrder.objects.get(pk=1)
|
|
||||||
|
|
||||||
self.assertEqual(order.get_absolute_url(), '/order/purchase-order/1/')
|
for pk in range(1, 8):
|
||||||
|
|
||||||
self.assertEqual(str(order), 'PO0001 - ACME')
|
order = PurchaseOrder.objects.get(pk=pk)
|
||||||
|
|
||||||
|
self.assertEqual(order.get_absolute_url(), f'/order/purchase-order/{pk}/')
|
||||||
|
|
||||||
|
self.assertEqual(order.reference, f'PO-{pk:04d}')
|
||||||
|
|
||||||
line = PurchaseOrderLineItem.objects.get(pk=1)
|
line = PurchaseOrderLineItem.objects.get(pk=1)
|
||||||
|
self.assertEqual(str(line), "100 x ACME0001 from ACME (for PO-0001 - ACME)")
|
||||||
self.assertEqual(str(line), "100 x ACME0001 from ACME (for PO0001 - ACME)")
|
|
||||||
|
|
||||||
def test_rebuild_reference(self):
|
def test_rebuild_reference(self):
|
||||||
"""Test that the reference_int field is correctly updated when the model is saved"""
|
"""Test that the reference_int field is correctly updated when the model is saved"""
|
||||||
|
|||||||
@@ -0,0 +1,49 @@
|
|||||||
|
"""Validation methods for the order app"""
|
||||||
|
|
||||||
|
|
||||||
|
def generate_next_sales_order_reference():
|
||||||
|
"""Generate the next available SalesOrder reference"""
|
||||||
|
|
||||||
|
from order.models import SalesOrder
|
||||||
|
|
||||||
|
return SalesOrder.generate_reference()
|
||||||
|
|
||||||
|
|
||||||
|
def generate_next_purchase_order_reference():
|
||||||
|
"""Generate the next available PurchasesOrder reference"""
|
||||||
|
|
||||||
|
from order.models import PurchaseOrder
|
||||||
|
|
||||||
|
return PurchaseOrder.generate_reference()
|
||||||
|
|
||||||
|
|
||||||
|
def validate_sales_order_reference_pattern(pattern):
|
||||||
|
"""Validate the SalesOrder reference 'pattern' setting"""
|
||||||
|
|
||||||
|
from order.models import SalesOrder
|
||||||
|
|
||||||
|
SalesOrder.validate_reference_pattern(pattern)
|
||||||
|
|
||||||
|
|
||||||
|
def validate_purchase_order_reference_pattern(pattern):
|
||||||
|
"""Validate the PurchaseOrder reference 'pattern' setting"""
|
||||||
|
|
||||||
|
from order.models import PurchaseOrder
|
||||||
|
|
||||||
|
PurchaseOrder.validate_reference_pattern(pattern)
|
||||||
|
|
||||||
|
|
||||||
|
def validate_sales_order_reference(value):
|
||||||
|
"""Validate that the SalesOrder reference field matches the required pattern"""
|
||||||
|
|
||||||
|
from order.models import SalesOrder
|
||||||
|
|
||||||
|
SalesOrder.validate_reference_field(value)
|
||||||
|
|
||||||
|
|
||||||
|
def validate_purchase_order_reference(value):
|
||||||
|
"""Validate that the PurchaseOrder reference field matches the required pattern"""
|
||||||
|
|
||||||
|
from order.models import PurchaseOrder
|
||||||
|
|
||||||
|
PurchaseOrder.validate_reference_field(value)
|
||||||
@@ -1545,6 +1545,20 @@ class BomFilter(rest_filters.FilterSet):
|
|||||||
|
|
||||||
return queryset
|
return queryset
|
||||||
|
|
||||||
|
on_order = rest_filters.BooleanFilter(label="On order", method="filter_on_order")
|
||||||
|
|
||||||
|
def filter_on_order(self, queryset, name, value):
|
||||||
|
"""Filter the queryset based on whether each line item has any stock on order"""
|
||||||
|
|
||||||
|
value = str2bool(value)
|
||||||
|
|
||||||
|
if value:
|
||||||
|
queryset = queryset.filter(on_order__gt=0)
|
||||||
|
else:
|
||||||
|
queryset = queryset.filter(on_order=0)
|
||||||
|
|
||||||
|
return queryset
|
||||||
|
|
||||||
|
|
||||||
class BomList(ListCreateDestroyAPIView):
|
class BomList(ListCreateDestroyAPIView):
|
||||||
"""API endpoint for accessing a list of BomItem objects.
|
"""API endpoint for accessing a list of BomItem objects.
|
||||||
|
|||||||
@@ -524,6 +524,8 @@ class BomItemSerializer(InvenTreeModelSerializer):
|
|||||||
|
|
||||||
purchase_price_range = serializers.SerializerMethodField()
|
purchase_price_range = serializers.SerializerMethodField()
|
||||||
|
|
||||||
|
on_order = serializers.FloatField(read_only=True)
|
||||||
|
|
||||||
# Annotated fields for available stock
|
# Annotated fields for available stock
|
||||||
available_stock = serializers.FloatField(read_only=True)
|
available_stock = serializers.FloatField(read_only=True)
|
||||||
available_substitute_stock = serializers.FloatField(read_only=True)
|
available_substitute_stock = serializers.FloatField(read_only=True)
|
||||||
@@ -593,6 +595,11 @@ class BomItemSerializer(InvenTreeModelSerializer):
|
|||||||
|
|
||||||
ref = 'sub_part__'
|
ref = 'sub_part__'
|
||||||
|
|
||||||
|
# Annotate with the total "on order" amount for the sub-part
|
||||||
|
queryset = queryset.annotate(
|
||||||
|
on_order=part.filters.annotate_on_order_quantity(ref),
|
||||||
|
)
|
||||||
|
|
||||||
# Calculate "total stock" for the referenced sub_part
|
# Calculate "total stock" for the referenced sub_part
|
||||||
# Calculate the "build_order_allocations" for the sub_part
|
# Calculate the "build_order_allocations" for the sub_part
|
||||||
# Note that these fields are only aliased, not annotated
|
# Note that these fields are only aliased, not annotated
|
||||||
@@ -719,6 +726,8 @@ class BomItemSerializer(InvenTreeModelSerializer):
|
|||||||
'available_substitute_stock',
|
'available_substitute_stock',
|
||||||
'available_variant_stock',
|
'available_variant_stock',
|
||||||
|
|
||||||
|
# Annotated field describing quantity on order
|
||||||
|
'on_order',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1514,6 +1514,7 @@ class PartAPIAggregationTest(InvenTreeAPITestCase):
|
|||||||
part=Part.objects.get(pk=101),
|
part=Part.objects.get(pk=101),
|
||||||
quantity=10,
|
quantity=10,
|
||||||
title='Making some assemblies',
|
title='Making some assemblies',
|
||||||
|
reference='BO-9999',
|
||||||
status=BuildStatus.PRODUCTION,
|
status=BuildStatus.PRODUCTION,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import os
|
|||||||
import pathlib
|
import pathlib
|
||||||
import warnings
|
import warnings
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
from importlib.metadata import metadata
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.db.utils import OperationalError, ProgrammingError
|
from django.db.utils import OperationalError, ProgrammingError
|
||||||
@@ -195,11 +196,26 @@ class InvenTreePlugin(MixinBase, MetaBase):
|
|||||||
|
|
||||||
self.define_package()
|
self.define_package()
|
||||||
|
|
||||||
|
def _get_value(self, meta_name: str, package_name: str) -> str:
|
||||||
|
"""Extract values from class meta or package info.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
meta_name (str): Name of the class meta to use.
|
||||||
|
package_name (str): Name of the package data to use.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: Extracted value, None if nothing found.
|
||||||
|
"""
|
||||||
|
val = getattr(self, meta_name, None)
|
||||||
|
if not val:
|
||||||
|
val = self.package.get(package_name, None)
|
||||||
|
return val
|
||||||
|
|
||||||
# region properties
|
# region properties
|
||||||
@property
|
@property
|
||||||
def description(self):
|
def description(self):
|
||||||
"""Description of plugin."""
|
"""Description of plugin."""
|
||||||
description = getattr(self, 'DESCRIPTION', None)
|
description = self._get_value('DESCRIPTION', 'description')
|
||||||
if not description:
|
if not description:
|
||||||
description = self.plugin_name()
|
description = self.plugin_name()
|
||||||
return description
|
return description
|
||||||
@@ -207,9 +223,7 @@ class InvenTreePlugin(MixinBase, MetaBase):
|
|||||||
@property
|
@property
|
||||||
def author(self):
|
def author(self):
|
||||||
"""Author of plugin - either from plugin settings or git."""
|
"""Author of plugin - either from plugin settings or git."""
|
||||||
author = getattr(self, 'AUTHOR', None)
|
author = self._get_value('AUTHOR', 'author')
|
||||||
if not author:
|
|
||||||
author = self.package.get('author')
|
|
||||||
if not author:
|
if not author:
|
||||||
author = _('No author found') # pragma: no cover
|
author = _('No author found') # pragma: no cover
|
||||||
return author
|
return author
|
||||||
@@ -229,19 +243,19 @@ class InvenTreePlugin(MixinBase, MetaBase):
|
|||||||
@property
|
@property
|
||||||
def version(self):
|
def version(self):
|
||||||
"""Version of plugin."""
|
"""Version of plugin."""
|
||||||
version = getattr(self, 'VERSION', None)
|
version = self._get_value('VERSION', 'version')
|
||||||
return version
|
return version
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def website(self):
|
def website(self):
|
||||||
"""Website of plugin - if set else None."""
|
"""Website of plugin - if set else None."""
|
||||||
website = getattr(self, 'WEBSITE', None)
|
website = self._get_value('WEBSITE', 'website')
|
||||||
return website
|
return website
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def license(self):
|
def license(self):
|
||||||
"""License of plugin."""
|
"""License of plugin."""
|
||||||
lic = getattr(self, 'LICENSE', None)
|
lic = self._get_value('LICENSE', 'license')
|
||||||
return lic
|
return lic
|
||||||
# endregion
|
# endregion
|
||||||
|
|
||||||
@@ -273,9 +287,18 @@ class InvenTreePlugin(MixinBase, MetaBase):
|
|||||||
"""Get last git commit for the plugin."""
|
"""Get last git commit for the plugin."""
|
||||||
return get_git_log(self.def_path)
|
return get_git_log(self.def_path)
|
||||||
|
|
||||||
def _get_package_metadata(self):
|
@classmethod
|
||||||
|
def _get_package_metadata(cls):
|
||||||
"""Get package metadata for plugin."""
|
"""Get package metadata for plugin."""
|
||||||
return {} # pragma: no cover # TODO add usage for package metadata
|
meta = metadata(cls.__name__)
|
||||||
|
|
||||||
|
return {
|
||||||
|
'author': meta['Author-email'],
|
||||||
|
'description': meta['Summary'],
|
||||||
|
'version': meta['Version'],
|
||||||
|
'website': meta['Project-URL'],
|
||||||
|
'license': meta['License']
|
||||||
|
}
|
||||||
|
|
||||||
def define_package(self):
|
def define_package(self):
|
||||||
"""Add package info of the plugin into plugins context."""
|
"""Add package info of the plugin into plugins context."""
|
||||||
|
|||||||
@@ -208,6 +208,7 @@ class PluginsRegistry:
|
|||||||
try:
|
try:
|
||||||
plugin = entry.load()
|
plugin = entry.load()
|
||||||
plugin.is_package = True
|
plugin.is_package = True
|
||||||
|
plugin._get_package_metadata()
|
||||||
self.plugin_modules.append(plugin)
|
self.plugin_modules.append(plugin)
|
||||||
except Exception as error:
|
except Exception as error:
|
||||||
handle_error(error, do_raise=False, log_name='discovery')
|
handle_error(error, do_raise=False, log_name='discovery')
|
||||||
|
|||||||
@@ -425,7 +425,6 @@ class PurchaseOrderReport(ReportTemplateBase):
|
|||||||
'order': order,
|
'order': order,
|
||||||
'reference': order.reference,
|
'reference': order.reference,
|
||||||
'supplier': order.supplier,
|
'supplier': order.supplier,
|
||||||
'prefix': common.models.InvenTreeSetting.get_setting('PURCHASEORDER_REFERENCE_PREFIX'),
|
|
||||||
'title': str(order),
|
'title': str(order),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -463,7 +462,6 @@ class SalesOrderReport(ReportTemplateBase):
|
|||||||
'lines': order.lines,
|
'lines': order.lines,
|
||||||
'extra_lines': order.extra_lines,
|
'extra_lines': order.extra_lines,
|
||||||
'order': order,
|
'order': order,
|
||||||
'prefix': common.models.InvenTreeSetting.get_setting('SALESORDER_REFERENCE_PREFIX'),
|
|
||||||
'reference': order.reference,
|
'reference': order.reference,
|
||||||
'title': str(order),
|
'title': str(order),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,8 +30,7 @@ import report.models
|
|||||||
from company import models as CompanyModels
|
from company import models as CompanyModels
|
||||||
from InvenTree.fields import (InvenTreeModelMoneyField, InvenTreeNotesField,
|
from InvenTree.fields import (InvenTreeModelMoneyField, InvenTreeNotesField,
|
||||||
InvenTreeURLField)
|
InvenTreeURLField)
|
||||||
from InvenTree.models import InvenTreeAttachment, InvenTreeTree
|
from InvenTree.models import InvenTreeAttachment, InvenTreeTree, extract_int
|
||||||
from InvenTree.serializers import extract_int
|
|
||||||
from InvenTree.status_codes import StockHistoryCode, StockStatus
|
from InvenTree.status_codes import StockHistoryCode, StockStatus
|
||||||
from part import models as PartModels
|
from part import models as PartModels
|
||||||
from plugin.events import trigger_event
|
from plugin.events import trigger_event
|
||||||
@@ -1708,8 +1707,7 @@ class StockItem(MetadataMixin, MPTTModel):
|
|||||||
s += ' @ {loc}'.format(loc=self.location.name)
|
s += ' @ {loc}'.format(loc=self.location.name)
|
||||||
|
|
||||||
if self.purchase_order:
|
if self.purchase_order:
|
||||||
s += " ({pre}{po})".format(
|
s += " ({po})".format(
|
||||||
pre=InvenTree.helpers.getSetting("PURCHASEORDER_REFERENCE_PREFIX"),
|
|
||||||
po=self.purchase_order,
|
po=self.purchase_order,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,8 @@ import InvenTree.serializers
|
|||||||
import part.models as part_models
|
import part.models as part_models
|
||||||
from common.settings import currency_code_default, currency_code_mappings
|
from common.settings import currency_code_default, currency_code_mappings
|
||||||
from company.serializers import SupplierPartSerializer
|
from company.serializers import SupplierPartSerializer
|
||||||
from InvenTree.serializers import InvenTreeDecimalField, extract_int
|
from InvenTree.models import extract_int
|
||||||
|
from InvenTree.serializers import InvenTreeDecimalField
|
||||||
from part.serializers import PartBriefSerializer
|
from part.serializers import PartBriefSerializer
|
||||||
|
|
||||||
from .models import (StockItem, StockItemAttachment, StockItemTestResult,
|
from .models import (StockItem, StockItemAttachment, StockItemTestResult,
|
||||||
@@ -67,8 +68,8 @@ class StockItemSerializerBrief(InvenTree.serializers.InvenTreeModelSerializer):
|
|||||||
|
|
||||||
def validate_serial(self, value):
|
def validate_serial(self, value):
|
||||||
"""Make sure serial is not to big."""
|
"""Make sure serial is not to big."""
|
||||||
if extract_int(value) > 2147483647:
|
if abs(extract_int(value)) > 0x7fffffff:
|
||||||
raise serializers.ValidationError('serial is to to big')
|
raise serializers.ValidationError(_("Serial number is too large"))
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -297,6 +297,7 @@
|
|||||||
stock_item: {{ item.pk }},
|
stock_item: {{ item.pk }},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
multi_delete: true,
|
||||||
method: 'DELETE',
|
method: 'DELETE',
|
||||||
title: '{% trans "Delete Test Data" %}',
|
title: '{% trans "Delete Test Data" %}',
|
||||||
preFormContent: html,
|
preFormContent: html,
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ class StockTest(InvenTreeTestCase):
|
|||||||
# And there should be *no* items being build
|
# And there should be *no* items being build
|
||||||
self.assertEqual(part.quantity_being_built, 0)
|
self.assertEqual(part.quantity_being_built, 0)
|
||||||
|
|
||||||
build = Build.objects.create(reference='12345', part=part, title='A test build', quantity=1)
|
build = Build.objects.create(reference='BO-4444', part=part, title='A test build', quantity=1)
|
||||||
|
|
||||||
# Add some stock items which are "building"
|
# Add some stock items which are "building"
|
||||||
for _ in range(10):
|
for _ in range(10):
|
||||||
@@ -395,13 +395,14 @@ class StockTest(InvenTreeTestCase):
|
|||||||
item.serial = "-123"
|
item.serial = "-123"
|
||||||
item.save()
|
item.save()
|
||||||
|
|
||||||
# Negative number should map to zero
|
# Negative number should map to positive value
|
||||||
self.assertEqual(item.serial_int, 0)
|
self.assertEqual(item.serial_int, 123)
|
||||||
|
|
||||||
# Test a very very large value
|
# Test a very very large value
|
||||||
item.serial = '99999999999999999999999999999999999999999999999999999'
|
item.serial = '99999999999999999999999999999999999999999999999999999'
|
||||||
item.save()
|
item.save()
|
||||||
|
|
||||||
|
# The 'integer' portion has been clipped to a maximum value
|
||||||
self.assertEqual(item.serial_int, 0x7fffffff)
|
self.assertEqual(item.serial_int, 0x7fffffff)
|
||||||
|
|
||||||
# Non-numeric values should encode to zero
|
# Non-numeric values should encode to zero
|
||||||
|
|||||||
@@ -72,6 +72,7 @@ $('#history-delete').click(function() {
|
|||||||
'{% url "api-notifications-list" %}',
|
'{% url "api-notifications-list" %}',
|
||||||
{
|
{
|
||||||
method: 'DELETE',
|
method: 'DELETE',
|
||||||
|
multi_delete: true,
|
||||||
preFormContent: html,
|
preFormContent: html,
|
||||||
title: '{% trans "Delete Notifications" %}',
|
title: '{% trans "Delete Notifications" %}',
|
||||||
onSuccess: function() {
|
onSuccess: function() {
|
||||||
|
|||||||
@@ -12,8 +12,7 @@
|
|||||||
|
|
||||||
<table class='table table-striped table-condensed'>
|
<table class='table table-striped table-condensed'>
|
||||||
<tbody>
|
<tbody>
|
||||||
{% include "InvenTree/settings/setting.html" with key="BUILDORDER_REFERENCE_PREFIX" %}
|
{% include "InvenTree/settings/setting.html" with key="BUILDORDER_REFERENCE_PATTERN" %}
|
||||||
{% include "InvenTree/settings/setting.html" with key="BUILDORDER_REFERENCE_REGEX" %}
|
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,9 @@
|
|||||||
{% include "InvenTree/settings/setting.html" with key="INVENTREE_RESTRICT_ABOUT" icon="fa-info-circle" %}
|
{% include "InvenTree/settings/setting.html" with key="INVENTREE_RESTRICT_ABOUT" icon="fa-info-circle" %}
|
||||||
{% include "InvenTree/settings/setting.html" with key="INVENTREE_BASE_URL" icon="fa-globe" %}
|
{% include "InvenTree/settings/setting.html" with key="INVENTREE_BASE_URL" icon="fa-globe" %}
|
||||||
{% include "InvenTree/settings/setting.html" with key="INVENTREE_COMPANY_NAME" icon="fa-building" %}
|
{% include "InvenTree/settings/setting.html" with key="INVENTREE_COMPANY_NAME" icon="fa-building" %}
|
||||||
|
<tr><td colspan='5'></td></tr>
|
||||||
{% include "InvenTree/settings/setting.html" with key="INVENTREE_DOWNLOAD_FROM_URL" icon="fa-cloud-download-alt" %}
|
{% include "InvenTree/settings/setting.html" with key="INVENTREE_DOWNLOAD_FROM_URL" icon="fa-cloud-download-alt" %}
|
||||||
|
{% include "InvenTree/settings/setting.html" with key="INVENTREE_REQUIRE_CONFIRM" icon="fa-check" %}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
{% block content %}
|
{% block content %}
|
||||||
<table class='table table-striped table-condensed'>
|
<table class='table table-striped table-condensed'>
|
||||||
<tbody>
|
<tbody>
|
||||||
{% include "InvenTree/settings/setting.html" with key="PURCHASEORDER_REFERENCE_PREFIX" %}
|
{% include "InvenTree/settings/setting.html" with key="PURCHASEORDER_REFERENCE_PATTERN" %}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
<table class='table table-striped table-condensed'>
|
<table class='table table-striped table-condensed'>
|
||||||
<tbody>
|
<tbody>
|
||||||
{% include "InvenTree/settings/setting.html" with key="SALESORDER_REFERENCE_PREFIX" %}
|
{% include "InvenTree/settings/setting.html" with key="SALESORDER_REFERENCE_PATTERN" %}
|
||||||
{% include "InvenTree/settings/setting.html" with key="SALESORDER_DEFAULT_SHIPMENT" icon="fa-truck-loading" %}
|
{% include "InvenTree/settings/setting.html" with key="SALESORDER_DEFAULT_SHIPMENT" icon="fa-truck-loading" %}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|||||||
@@ -81,7 +81,7 @@
|
|||||||
<td>
|
<td>
|
||||||
<span style="display: none;" id="about-copy-text">{% include "version.html" %}</span>
|
<span style="display: none;" id="about-copy-text">{% include "version.html" %}</span>
|
||||||
<span class="float-right">
|
<span class="float-right">
|
||||||
<button class="btn clip-btn-version" type="button" data-bs-toggle='tooltip' title='{% trans "copy to clipboard" %}'><em class="fas fa-copy"></em> {% trans "copy version information" %}</button>
|
<button class="btn clip-btn" type="button" data-bs-toggle='tooltip' title='{% trans "copy to clipboard" %}'><em class="fas fa-copy"></em> {% trans "copy version information" %}</button>
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|||||||
@@ -109,6 +109,7 @@ function deleteAttachments(attachments, url, options={}) {
|
|||||||
|
|
||||||
constructForm(url, {
|
constructForm(url, {
|
||||||
method: 'DELETE',
|
method: 'DELETE',
|
||||||
|
multi_delete: true,
|
||||||
title: '{% trans "Delete Attachments" %}',
|
title: '{% trans "Delete Attachments" %}',
|
||||||
preFormContent: html,
|
preFormContent: html,
|
||||||
form_data: {
|
form_data: {
|
||||||
|
|||||||
@@ -292,8 +292,8 @@ function exportBom(part_id, options={}) {
|
|||||||
choices: exportFormatOptions(),
|
choices: exportFormatOptions(),
|
||||||
},
|
},
|
||||||
cascade: {
|
cascade: {
|
||||||
label: '{% trans "Cascading" %}',
|
label: '{% trans "Multi Level BOM" %}',
|
||||||
help_text: '{% trans "Download cascading / multi-level BOM" %}',
|
help_text: '{% trans "Include BOM data for subassemblies" %}',
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
value: inventreeLoad('bom-export-cascading', true),
|
value: inventreeLoad('bom-export-cascading', true),
|
||||||
},
|
},
|
||||||
@@ -302,6 +302,7 @@ function exportBom(part_id, options={}) {
|
|||||||
help_text: '{% trans "Select maximum number of BOM levels to export (0 = all levels)" %}',
|
help_text: '{% trans "Select maximum number of BOM levels to export (0 = all levels)" %}',
|
||||||
type: 'integer',
|
type: 'integer',
|
||||||
value: 0,
|
value: 0,
|
||||||
|
required: true,
|
||||||
min_value: 0,
|
min_value: 0,
|
||||||
},
|
},
|
||||||
parameter_data: {
|
parameter_data: {
|
||||||
@@ -651,9 +652,10 @@ function bomSubstitutesDialog(bom_item_id, substitutes, options={}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Delete the selected BOM items from the database
|
||||||
|
*/
|
||||||
function deleteBomItems(items, options={}) {
|
function deleteBomItems(items, options={}) {
|
||||||
/* Delete the selected BOM items from the database
|
|
||||||
*/
|
|
||||||
|
|
||||||
function renderItem(item, opts={}) {
|
function renderItem(item, opts={}) {
|
||||||
|
|
||||||
@@ -696,6 +698,7 @@ function deleteBomItems(items, options={}) {
|
|||||||
|
|
||||||
constructForm('{% url "api-bom-list" %}', {
|
constructForm('{% url "api-bom-list" %}', {
|
||||||
method: 'DELETE',
|
method: 'DELETE',
|
||||||
|
multi_delete: true,
|
||||||
title: '{% trans "Delete selected BOM items?" %}',
|
title: '{% trans "Delete selected BOM items?" %}',
|
||||||
form_data: {
|
form_data: {
|
||||||
items: ids,
|
items: ids,
|
||||||
@@ -877,6 +880,32 @@ function loadBomTable(table, options={}) {
|
|||||||
|
|
||||||
return text;
|
return text;
|
||||||
},
|
},
|
||||||
|
footerFormatter: function(data) {
|
||||||
|
|
||||||
|
// Top-level BOM count
|
||||||
|
var top_total = 0;
|
||||||
|
|
||||||
|
// Total BOM count
|
||||||
|
var all_total = 0;
|
||||||
|
|
||||||
|
data.forEach(function(row) {
|
||||||
|
var q = +row['quantity'] || 0;
|
||||||
|
|
||||||
|
all_total += q;
|
||||||
|
|
||||||
|
if (row.part == options.parent_id) {
|
||||||
|
top_total += q;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var total = `${top_total}`;
|
||||||
|
|
||||||
|
if (top_total != all_total) {
|
||||||
|
total += ` / ${all_total}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return total;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
cols.push({
|
cols.push({
|
||||||
@@ -897,9 +926,10 @@ function loadBomTable(table, options={}) {
|
|||||||
var text = `${available_stock}`;
|
var text = `${available_stock}`;
|
||||||
|
|
||||||
if (available_stock <= 0) {
|
if (available_stock <= 0) {
|
||||||
text = `<span class='badge rounded-pill bg-danger'>{% trans "No Stock Available" %}</span>`;
|
text += `<span class='fas fa-times-circle icon-red float-right' title='{% trans "No Stock Available" %}'></span>`;
|
||||||
} else {
|
} else {
|
||||||
var extra = '';
|
var extra = '';
|
||||||
|
|
||||||
if ((substitute_stock > 0) && (variant_stock > 0)) {
|
if ((substitute_stock > 0) && (variant_stock > 0)) {
|
||||||
extra = '{% trans "Includes variant and substitute stock" %}';
|
extra = '{% trans "Includes variant and substitute stock" %}';
|
||||||
} else if (variant_stock > 0) {
|
} else if (variant_stock > 0) {
|
||||||
@@ -913,6 +943,10 @@ function loadBomTable(table, options={}) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (row.on_order && row.on_order > 0) {
|
||||||
|
text += `<span class='fas fa-shopping-cart float-right' title='{% trans "On Order" %}: ${row.on_order}'></span>`;
|
||||||
|
}
|
||||||
|
|
||||||
return renderLink(text, url);
|
return renderLink(text, url);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -1010,7 +1044,36 @@ function loadBomTable(table, options={}) {
|
|||||||
can_build = available / row.quantity;
|
can_build = available / row.quantity;
|
||||||
}
|
}
|
||||||
|
|
||||||
return formatDecimal(can_build, 2);
|
var text = formatDecimal(can_build, 2);
|
||||||
|
|
||||||
|
// Take "on order" quantity into account
|
||||||
|
if (row.on_order && row.on_order > 0 && row.quantity > 0) {
|
||||||
|
available += row.on_order;
|
||||||
|
can_build = available / row.quantity;
|
||||||
|
|
||||||
|
text += `<span class='fas fa-info-circle icon-blue float-right' title='{% trans "Including On Order" %}: ${can_build}'></span>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return text;
|
||||||
|
},
|
||||||
|
footerFormatter: function(data) {
|
||||||
|
var can_build = null;
|
||||||
|
|
||||||
|
data.forEach(function(row) {
|
||||||
|
if (row.part == options.parent_id && row.quantity > 0) {
|
||||||
|
var cb = availableQuantity(row) / row.quantity;
|
||||||
|
|
||||||
|
if (can_build == null || cb < can_build) {
|
||||||
|
can_build = cb;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (can_build == null) {
|
||||||
|
can_build = '-';
|
||||||
|
}
|
||||||
|
|
||||||
|
return can_build;
|
||||||
},
|
},
|
||||||
sorter: function(valA, valB, rowA, rowB) {
|
sorter: function(valA, valB, rowA, rowB) {
|
||||||
// Function to sort the "can build" quantity
|
// Function to sort the "can build" quantity
|
||||||
@@ -1131,6 +1194,7 @@ function loadBomTable(table, options={}) {
|
|||||||
parentIdField: 'parentId',
|
parentIdField: 'parentId',
|
||||||
treeShowField: 'sub_part',
|
treeShowField: 'sub_part',
|
||||||
showColumns: true,
|
showColumns: true,
|
||||||
|
showFooter: true,
|
||||||
name: 'bom',
|
name: 'bom',
|
||||||
sortable: true,
|
sortable: true,
|
||||||
search: true,
|
search: true,
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
/* globals
|
/* globals
|
||||||
buildStatusDisplay,
|
buildStatusDisplay,
|
||||||
constructForm,
|
constructForm,
|
||||||
global_settings,
|
|
||||||
imageHoverIcon,
|
imageHoverIcon,
|
||||||
inventreeGet,
|
inventreeGet,
|
||||||
launchModalForm,
|
launchModalForm,
|
||||||
@@ -36,7 +35,7 @@
|
|||||||
function buildFormFields() {
|
function buildFormFields() {
|
||||||
return {
|
return {
|
||||||
reference: {
|
reference: {
|
||||||
prefix: global_settings.BUILDORDER_REFERENCE_PREFIX,
|
icon: 'fa-hashtag',
|
||||||
},
|
},
|
||||||
part: {
|
part: {
|
||||||
filters: {
|
filters: {
|
||||||
@@ -731,9 +730,8 @@ function loadBuildOrderAllocationTable(table, options={}) {
|
|||||||
switchable: false,
|
switchable: false,
|
||||||
title: '{% trans "Build Order" %}',
|
title: '{% trans "Build Order" %}',
|
||||||
formatter: function(value, row) {
|
formatter: function(value, row) {
|
||||||
var prefix = global_settings.BUILDORDER_REFERENCE_PREFIX;
|
|
||||||
|
|
||||||
var ref = `${prefix}${row.build_detail.reference}`;
|
var ref = `${row.build_detail.reference}`;
|
||||||
|
|
||||||
return renderLink(ref, `/build/${row.build}/`);
|
return renderLink(ref, `/build/${row.build}/`);
|
||||||
}
|
}
|
||||||
@@ -2372,7 +2370,6 @@ function loadBuildTable(table, options) {
|
|||||||
filters,
|
filters,
|
||||||
{
|
{
|
||||||
success: function(response) {
|
success: function(response) {
|
||||||
var prefix = global_settings.BUILDORDER_REFERENCE_PREFIX;
|
|
||||||
|
|
||||||
for (var idx = 0; idx < response.length; idx++) {
|
for (var idx = 0; idx < response.length; idx++) {
|
||||||
|
|
||||||
@@ -2386,7 +2383,7 @@ function loadBuildTable(table, options) {
|
|||||||
date = order.target_date;
|
date = order.target_date;
|
||||||
}
|
}
|
||||||
|
|
||||||
var title = `${prefix}${order.reference}`;
|
var title = `${order.reference}`;
|
||||||
|
|
||||||
var color = '#4c68f5';
|
var color = '#4c68f5';
|
||||||
|
|
||||||
@@ -2460,12 +2457,6 @@ function loadBuildTable(table, options) {
|
|||||||
switchable: true,
|
switchable: true,
|
||||||
formatter: function(value, row) {
|
formatter: function(value, row) {
|
||||||
|
|
||||||
var prefix = global_settings.BUILDORDER_REFERENCE_PREFIX;
|
|
||||||
|
|
||||||
if (prefix) {
|
|
||||||
value = `${prefix}${value}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
var html = renderLink(value, '/build/' + row.pk + '/');
|
var html = renderLink(value, '/build/' + row.pk + '/');
|
||||||
|
|
||||||
if (row.overdue) {
|
if (row.overdue) {
|
||||||
|
|||||||
@@ -263,6 +263,7 @@ function deleteSupplierParts(parts, options={}) {
|
|||||||
|
|
||||||
constructForm('{% url "api-supplier-part-list" %}', {
|
constructForm('{% url "api-supplier-part-list" %}', {
|
||||||
method: 'DELETE',
|
method: 'DELETE',
|
||||||
|
multi_delete: true,
|
||||||
title: '{% trans "Delete Supplier Parts" %}',
|
title: '{% trans "Delete Supplier Parts" %}',
|
||||||
preFormContent: html,
|
preFormContent: html,
|
||||||
form_data: {
|
form_data: {
|
||||||
@@ -491,6 +492,7 @@ function deleteManufacturerParts(selections, options={}) {
|
|||||||
|
|
||||||
constructForm('{% url "api-manufacturer-part-list" %}', {
|
constructForm('{% url "api-manufacturer-part-list" %}', {
|
||||||
method: 'DELETE',
|
method: 'DELETE',
|
||||||
|
multi_delete: true,
|
||||||
title: '{% trans "Delete Manufacturer Parts" %}',
|
title: '{% trans "Delete Manufacturer Parts" %}',
|
||||||
preFormContent: html,
|
preFormContent: html,
|
||||||
form_data: {
|
form_data: {
|
||||||
@@ -538,6 +540,7 @@ function deleteManufacturerPartParameters(selections, options={}) {
|
|||||||
|
|
||||||
constructForm('{% url "api-manufacturer-part-parameter-list" %}', {
|
constructForm('{% url "api-manufacturer-part-parameter-list" %}', {
|
||||||
method: 'DELETE',
|
method: 'DELETE',
|
||||||
|
multi_delete: true,
|
||||||
title: '{% trans "Delete Parameters" %}',
|
title: '{% trans "Delete Parameters" %}',
|
||||||
preFormContent: html,
|
preFormContent: html,
|
||||||
form_data: {
|
form_data: {
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
inventreeFormDataUpload,
|
inventreeFormDataUpload,
|
||||||
inventreeGet,
|
inventreeGet,
|
||||||
inventreePut,
|
inventreePut,
|
||||||
|
global_settings,
|
||||||
modalEnable,
|
modalEnable,
|
||||||
modalShowSubmitButton,
|
modalShowSubmitButton,
|
||||||
renderBuild,
|
renderBuild,
|
||||||
@@ -250,30 +251,40 @@ function constructChangeForm(fields, options) {
|
|||||||
*/
|
*/
|
||||||
function constructDeleteForm(fields, options) {
|
function constructDeleteForm(fields, options) {
|
||||||
|
|
||||||
// Request existing data from the API endpoint
|
// If we are deleting a specific "instance" (i.e. a single object)
|
||||||
// This data can be used to render some information on the form
|
// then we request the instance information first
|
||||||
$.ajax({
|
|
||||||
url: options.url,
|
|
||||||
type: 'GET',
|
|
||||||
contentType: 'application/json',
|
|
||||||
dataType: 'json',
|
|
||||||
accepts: {
|
|
||||||
json: 'application/json',
|
|
||||||
},
|
|
||||||
success: function(data) {
|
|
||||||
|
|
||||||
// Store the instance data
|
// However we may be performing a "multi-delete" (against a list endpoint),
|
||||||
options.instance = data;
|
// in which case we do not want to perform such a request!
|
||||||
|
|
||||||
constructFormBody(fields, options);
|
if (options.multi_delete) {
|
||||||
},
|
constructFormBody(fields, options);
|
||||||
error: function(xhr) {
|
} else {
|
||||||
// TODO: Handle error here
|
// Request existing data from the API endpoint
|
||||||
console.error(`Error in constructDeleteForm at '${options.url}`);
|
// This data can be used to render some information on the form
|
||||||
|
$.ajax({
|
||||||
|
url: options.url,
|
||||||
|
type: 'GET',
|
||||||
|
contentType: 'application/json',
|
||||||
|
dataType: 'json',
|
||||||
|
accepts: {
|
||||||
|
json: 'application/json',
|
||||||
|
},
|
||||||
|
success: function(data) {
|
||||||
|
|
||||||
showApiError(xhr, options.url);
|
// Store the instance data
|
||||||
}
|
options.instance = data;
|
||||||
});
|
|
||||||
|
constructFormBody(fields, options);
|
||||||
|
},
|
||||||
|
error: function(xhr) {
|
||||||
|
// TODO: Handle error here
|
||||||
|
console.error(`Error in constructDeleteForm at '${options.url}`);
|
||||||
|
|
||||||
|
showApiError(xhr, options.url);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -565,7 +576,7 @@ function constructFormBody(fields, options) {
|
|||||||
$(modal).find('#modal-footer-buttons').html('');
|
$(modal).find('#modal-footer-buttons').html('');
|
||||||
|
|
||||||
// Insert "confirm" button (if required)
|
// Insert "confirm" button (if required)
|
||||||
if (options.confirm) {
|
if (options.confirm && global_settings.INVENTREE_REQUIRE_CONFIRM) {
|
||||||
insertConfirmButton(options);
|
insertConfirmButton(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -255,8 +255,7 @@ function renderOwner(name, data, parameters={}, options={}) {
|
|||||||
// eslint-disable-next-line no-unused-vars
|
// eslint-disable-next-line no-unused-vars
|
||||||
function renderPurchaseOrder(name, data, parameters={}, options={}) {
|
function renderPurchaseOrder(name, data, parameters={}, options={}) {
|
||||||
|
|
||||||
var prefix = global_settings.PURCHASEORDER_REFERENCE_PREFIX;
|
var html = `<span>${data.reference}</span>`;
|
||||||
var html = `<span>${prefix}${data.reference}</span>`;
|
|
||||||
|
|
||||||
var thumbnail = null;
|
var thumbnail = null;
|
||||||
|
|
||||||
@@ -281,8 +280,7 @@ function renderPurchaseOrder(name, data, parameters={}, options={}) {
|
|||||||
// eslint-disable-next-line no-unused-vars
|
// eslint-disable-next-line no-unused-vars
|
||||||
function renderSalesOrder(name, data, parameters={}, options={}) {
|
function renderSalesOrder(name, data, parameters={}, options={}) {
|
||||||
|
|
||||||
var prefix = global_settings.SALESORDER_REFERENCE_PREFIX;
|
var html = `<span>${data.reference}</span>`;
|
||||||
var html = `<span>${prefix}${data.reference}</span>`;
|
|
||||||
|
|
||||||
var thumbnail = null;
|
var thumbnail = null;
|
||||||
|
|
||||||
@@ -307,10 +305,8 @@ function renderSalesOrder(name, data, parameters={}, options={}) {
|
|||||||
// eslint-disable-next-line no-unused-vars
|
// eslint-disable-next-line no-unused-vars
|
||||||
function renderSalesOrderShipment(name, data, parameters={}, options={}) {
|
function renderSalesOrderShipment(name, data, parameters={}, options={}) {
|
||||||
|
|
||||||
var so_prefix = global_settings.SALESORDER_REFERENCE_PREFIX;
|
|
||||||
|
|
||||||
var html = `
|
var html = `
|
||||||
<span>${so_prefix}${data.order_detail.reference} - {% trans "Shipment" %} ${data.reference}</span>
|
<span>${data.order_detail.reference} - {% trans "Shipment" %} ${data.reference}</span>
|
||||||
<span class='float-right'>
|
<span class='float-right'>
|
||||||
<small>{% trans "Shipment ID" %}: ${data.pk}</small>
|
<small>{% trans "Shipment ID" %}: ${data.pk}</small>
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@@ -431,7 +431,7 @@ function createSalesOrderShipment(options={}) {
|
|||||||
var fields = salesOrderShipmentFields(options);
|
var fields = salesOrderShipmentFields(options);
|
||||||
|
|
||||||
fields.reference.value = ref;
|
fields.reference.value = ref;
|
||||||
fields.reference.prefix = global_settings.SALESORDER_REFERENCE_PREFIX + options.reference;
|
fields.reference.prefix = options.reference;
|
||||||
|
|
||||||
constructForm('{% url "api-so-shipment-list" %}', {
|
constructForm('{% url "api-so-shipment-list" %}', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
@@ -456,7 +456,7 @@ function createSalesOrder(options={}) {
|
|||||||
method: 'POST',
|
method: 'POST',
|
||||||
fields: {
|
fields: {
|
||||||
reference: {
|
reference: {
|
||||||
prefix: global_settings.SALESORDER_REFERENCE_PREFIX,
|
icon: 'fa-hashtag',
|
||||||
},
|
},
|
||||||
customer: {
|
customer: {
|
||||||
value: options.customer,
|
value: options.customer,
|
||||||
@@ -497,7 +497,7 @@ function createPurchaseOrder(options={}) {
|
|||||||
method: 'POST',
|
method: 'POST',
|
||||||
fields: {
|
fields: {
|
||||||
reference: {
|
reference: {
|
||||||
prefix: global_settings.PURCHASEORDER_REFERENCE_PREFIX,
|
icon: 'fa-hashtag',
|
||||||
},
|
},
|
||||||
supplier: {
|
supplier: {
|
||||||
icon: 'fa-building',
|
icon: 'fa-building',
|
||||||
@@ -1081,9 +1081,7 @@ function newPurchaseOrderFromOrderWizard(e) {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
success: function(response) {
|
success: function(response) {
|
||||||
var text = global_settings.PURCHASEORDER_REFERENCE_PREFIX || '';
|
var text = response.reference;
|
||||||
|
|
||||||
text += response.reference;
|
|
||||||
|
|
||||||
if (response.supplier_detail) {
|
if (response.supplier_detail) {
|
||||||
text += ` ${response.supplier_detail.name}`;
|
text += ` ${response.supplier_detail.name}`;
|
||||||
@@ -1545,8 +1543,6 @@ function loadPurchaseOrderTable(table, options) {
|
|||||||
filters,
|
filters,
|
||||||
{
|
{
|
||||||
success: function(response) {
|
success: function(response) {
|
||||||
var prefix = global_settings.PURCHASEORDER_REFERENCE_PREFIX;
|
|
||||||
|
|
||||||
for (var idx = 0; idx < response.length; idx++) {
|
for (var idx = 0; idx < response.length; idx++) {
|
||||||
|
|
||||||
var order = response[idx];
|
var order = response[idx];
|
||||||
@@ -1559,7 +1555,7 @@ function loadPurchaseOrderTable(table, options) {
|
|||||||
date = order.target_date;
|
date = order.target_date;
|
||||||
}
|
}
|
||||||
|
|
||||||
var title = `${prefix}${order.reference} - ${order.supplier_detail.name}`;
|
var title = `${order.reference} - ${order.supplier_detail.name}`;
|
||||||
|
|
||||||
var color = '#4c68f5';
|
var color = '#4c68f5';
|
||||||
|
|
||||||
@@ -1623,12 +1619,6 @@ function loadPurchaseOrderTable(table, options) {
|
|||||||
switchable: false,
|
switchable: false,
|
||||||
formatter: function(value, row) {
|
formatter: function(value, row) {
|
||||||
|
|
||||||
var prefix = global_settings.PURCHASEORDER_REFERENCE_PREFIX;
|
|
||||||
|
|
||||||
if (prefix) {
|
|
||||||
value = `${prefix}${value}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
var html = renderLink(value, `/order/purchase-order/${row.pk}/`);
|
var html = renderLink(value, `/order/purchase-order/${row.pk}/`);
|
||||||
|
|
||||||
if (row.overdue) {
|
if (row.overdue) {
|
||||||
@@ -2336,8 +2326,6 @@ function loadSalesOrderTable(table, options) {
|
|||||||
{
|
{
|
||||||
success: function(response) {
|
success: function(response) {
|
||||||
|
|
||||||
var prefix = global_settings.SALESORDER_REFERENCE_PREFIX;
|
|
||||||
|
|
||||||
for (var idx = 0; idx < response.length; idx++) {
|
for (var idx = 0; idx < response.length; idx++) {
|
||||||
var order = response[idx];
|
var order = response[idx];
|
||||||
|
|
||||||
@@ -2349,7 +2337,7 @@ function loadSalesOrderTable(table, options) {
|
|||||||
date = order.target_date;
|
date = order.target_date;
|
||||||
}
|
}
|
||||||
|
|
||||||
var title = `${prefix}${order.reference} - ${order.customer_detail.name}`;
|
var title = `${order.reference} - ${order.customer_detail.name}`;
|
||||||
|
|
||||||
// Default color is blue
|
// Default color is blue
|
||||||
var color = '#4c68f5';
|
var color = '#4c68f5';
|
||||||
@@ -2435,13 +2423,6 @@ function loadSalesOrderTable(table, options) {
|
|||||||
field: 'reference',
|
field: 'reference',
|
||||||
title: '{% trans "Sales Order" %}',
|
title: '{% trans "Sales Order" %}',
|
||||||
formatter: function(value, row) {
|
formatter: function(value, row) {
|
||||||
|
|
||||||
var prefix = global_settings.SALESORDER_REFERENCE_PREFIX;
|
|
||||||
|
|
||||||
if (prefix) {
|
|
||||||
value = `${prefix}${value}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
var html = renderLink(value, `/order/sales-order/${row.pk}/`);
|
var html = renderLink(value, `/order/sales-order/${row.pk}/`);
|
||||||
|
|
||||||
if (row.overdue) {
|
if (row.overdue) {
|
||||||
@@ -2891,7 +2872,7 @@ function allocateStockToSalesOrder(order_id, line_items, options={}) {
|
|||||||
var fields = salesOrderShipmentFields(options);
|
var fields = salesOrderShipmentFields(options);
|
||||||
|
|
||||||
fields.reference.value = ref;
|
fields.reference.value = ref;
|
||||||
fields.reference.prefix = global_settings.SALESORDER_REFERENCE_PREFIX + options.reference;
|
fields.reference.prefix = options.reference;
|
||||||
|
|
||||||
return fields;
|
return fields;
|
||||||
}
|
}
|
||||||
@@ -3123,9 +3104,7 @@ function loadSalesOrderAllocationTable(table, options={}) {
|
|||||||
title: '{% trans "Order" %}',
|
title: '{% trans "Order" %}',
|
||||||
formatter: function(value, row) {
|
formatter: function(value, row) {
|
||||||
|
|
||||||
var prefix = global_settings.SALESORDER_REFERENCE_PREFIX;
|
var ref = `${row.order_detail.reference}`;
|
||||||
|
|
||||||
var ref = `${prefix}${row.order_detail.reference}`;
|
|
||||||
|
|
||||||
return renderLink(ref, `/order/sales-order/${row.order}/`);
|
return renderLink(ref, `/order/sales-order/${row.order}/`);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -974,9 +974,7 @@ function loadPartPurchaseOrderTable(table, part_id, options={}) {
|
|||||||
return '-';
|
return '-';
|
||||||
}
|
}
|
||||||
|
|
||||||
var ref = global_settings.PURCHASEORDER_REFERENCE_PREFIX + order.reference;
|
var html = renderLink(order.reference, `/order/purchase-order/${order.pk}/`);
|
||||||
|
|
||||||
var html = renderLink(ref, `/order/purchase-order/${order.pk}/`);
|
|
||||||
|
|
||||||
html += purchaseOrderStatusDisplay(
|
html += purchaseOrderStatusDisplay(
|
||||||
order.status,
|
order.status,
|
||||||
|
|||||||
@@ -1916,10 +1916,7 @@ function loadStockTable(table, options) {
|
|||||||
var text = `${row.purchase_order}`;
|
var text = `${row.purchase_order}`;
|
||||||
|
|
||||||
if (row.purchase_order_reference) {
|
if (row.purchase_order_reference) {
|
||||||
|
text = row.purchase_order_reference;
|
||||||
var prefix = global_settings.PURCHASEORDER_REFERENCE_PREFIX;
|
|
||||||
|
|
||||||
text = prefix + row.purchase_order_reference;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return renderLink(text, link);
|
return renderLink(text, link);
|
||||||
|
|||||||
@@ -63,6 +63,10 @@ function getAvailableTableFilters(tableKey) {
|
|||||||
type: 'bool',
|
type: 'bool',
|
||||||
title: '{% trans "Has Available Stock" %}',
|
title: '{% trans "Has Available Stock" %}',
|
||||||
},
|
},
|
||||||
|
on_order: {
|
||||||
|
type: 'bool',
|
||||||
|
title: '{% trans "On Order" %}',
|
||||||
|
},
|
||||||
validated: {
|
validated: {
|
||||||
type: 'bool',
|
type: 'bool',
|
||||||
title: '{% trans "Validated" %}',
|
title: '{% trans "Validated" %}',
|
||||||
|
|||||||
+1
-1
@@ -71,7 +71,7 @@ django-allauth==0.51.0
|
|||||||
# via
|
# via
|
||||||
# -r requirements.in
|
# -r requirements.in
|
||||||
# django-allauth-2fa
|
# django-allauth-2fa
|
||||||
django-allauth-2fa==0.9
|
django-allauth-2fa==0.10.0
|
||||||
# via -r requirements.in
|
# via -r requirements.in
|
||||||
django-cleanup==6.0.0
|
django-cleanup==6.0.0
|
||||||
# via -r requirements.in
|
# via -r requirements.in
|
||||||
|
|||||||
Reference in New Issue
Block a user