diff --git a/.travis.yml b/.travis.yml index 29a1fe8db1..bdc0aad06c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,7 +7,7 @@ python: addons: apt-packages: - -sqlite3 + - sqlite3 before_install: - sudo apt-get update diff --git a/InvenTree/InvenTree/settings.py b/InvenTree/InvenTree/settings.py index 2ad7ae1c8b..e5f103f2a9 100644 --- a/InvenTree/InvenTree/settings.py +++ b/InvenTree/InvenTree/settings.py @@ -17,6 +17,8 @@ import logging import tempfile import yaml +from datetime import datetime + from django.utils.translation import gettext_lazy as _ @@ -101,6 +103,8 @@ INSTALLED_APPS = [ 'django_cleanup', # Automatically delete orphaned MEDIA files 'qr_code', # Generate QR codes 'mptt', # Modified Preorder Tree Traversal + 'markdownx', # Markdown editing + 'markdownify', # Markdown template rendering ] LOGGING = { @@ -161,6 +165,37 @@ REST_FRAMEWORK = { WSGI_APPLICATION = 'InvenTree.wsgi.application' +# Markdownx configuration +# Ref: https://neutronx.github.io/django-markdownx/customization/ +MARKDOWNX_MEDIA_PATH = datetime.now().strftime('markdownx/%Y/%m/%d') + +# Markdownify configuration +# Ref: https://django-markdownify.readthedocs.io/en/latest/settings.html + +MARKDOWNIFY_WHITELIST_TAGS = [ + 'a', + 'abbr', + 'b', + 'blockquote', + 'em', + 'h1', 'h2', 'h3', + 'i', + 'img', + 'li', + 'ol', + 'p', + 'strong', + 'ul' +] + +MARKDOWNIFY_WHITELIST_ATTRS = [ + 'href', + 'src', + 'alt', +] + +MARKDOWNIFY_BLEACH = True + DATABASES = {} """ diff --git a/InvenTree/InvenTree/static/css/inventree.css b/InvenTree/InvenTree/static/css/inventree.css index 579803410b..b920205ca3 100644 --- a/InvenTree/InvenTree/static/css/inventree.css +++ b/InvenTree/InvenTree/static/css/inventree.css @@ -5,6 +5,29 @@ --basic-color: #333; } +.markdownx .row { + margin: 5px; + padding: 5px; + border: 1px solid #cce; + border-radius: 4px; +} + +.markdownx-editor { + width: 100%; + border: 1px solid #cce; + border-radius: 3px; + padding: 10px; +} + +.panel-content { + padding: 10px; +} + +.markdownx-preview { + border: 1px solid #cce; + border-radius: 3px; + padding: 10px; +} .qr-code { max-width: 400px; @@ -305,6 +328,12 @@ width: 100%; } +input[type="submit"] { + color: #333; + background-color: #e6e6e6; + border-color: #adadad; +} + .modal textarea { width: 100%; } diff --git a/InvenTree/InvenTree/urls.py b/InvenTree/InvenTree/urls.py index 033261d9f8..31b498ea2b 100644 --- a/InvenTree/InvenTree/urls.py +++ b/InvenTree/InvenTree/urls.py @@ -100,6 +100,8 @@ urlpatterns = [ url(r'^api/', include(apipatterns)), url(r'^api-doc/', include_docs_urls(title='InvenTree API')), + + url(r'^markdownx/', include('markdownx.urls')), ] # Static file access diff --git a/InvenTree/InvenTree/version.py b/InvenTree/InvenTree/version.py index fb945fadd4..f5329effba 100644 --- a/InvenTree/InvenTree/version.py +++ b/InvenTree/InvenTree/version.py @@ -4,7 +4,7 @@ Provides information on the current InvenTree version import subprocess -INVENTREE_SW_VERSION = "0.0.7" +INVENTREE_SW_VERSION = "0.0.8" def inventreeVersion(): @@ -15,6 +15,12 @@ def inventreeVersion(): def inventreeCommitHash(): """ Returns the git commit hash for the running codebase """ - commit = str(subprocess.check_output('git rev-parse --short HEAD'.split()), 'utf-8').strip() + return str(subprocess.check_output('git rev-parse --short HEAD'.split()), 'utf-8').strip() - return commit + +def inventreeCommitDate(): + """ Returns the git commit date for the running codebase """ + + d = str(subprocess.check_output('git show -s --format=%ci'.split()), 'utf-8').strip() + + return d.split(' ')[0] diff --git a/InvenTree/build/forms.py b/InvenTree/build/forms.py index 54f651eade..4f9384d34e 100644 --- a/InvenTree/build/forms.py +++ b/InvenTree/build/forms.py @@ -26,7 +26,6 @@ class EditBuildForm(HelperForm): 'take_from', 'batch', 'URL', - 'notes', ] diff --git a/InvenTree/build/migrations/0008_auto_20200201_1247.py b/InvenTree/build/migrations/0008_auto_20200201_1247.py new file mode 100644 index 0000000000..99e916cd32 --- /dev/null +++ b/InvenTree/build/migrations/0008_auto_20200201_1247.py @@ -0,0 +1,19 @@ +# Generated by Django 2.2.9 on 2020-02-01 12:47 + +from django.db import migrations +import markdownx.models + + +class Migration(migrations.Migration): + + dependencies = [ + ('build', '0007_auto_20191118_2321'), + ] + + operations = [ + migrations.AlterField( + model_name='build', + name='notes', + field=markdownx.models.MarkdownxField(blank=True, help_text='Extra build notes'), + ), + ] diff --git a/InvenTree/build/models.py b/InvenTree/build/models.py index 51e1b7f5e7..1ad761a98e 100644 --- a/InvenTree/build/models.py +++ b/InvenTree/build/models.py @@ -16,6 +16,8 @@ from django.db import models, transaction from django.db.models import Sum from django.core.validators import MinValueValidator +from markdownx.models import MarkdownxField + from InvenTree.status_codes import BuildStatus from InvenTree.fields import InvenTreeURLField @@ -92,7 +94,7 @@ class Build(models.Model): URL = InvenTreeURLField(blank=True, help_text=_('Link to external URL')) - notes = models.TextField(blank=True, help_text=_('Extra build notes')) + notes = MarkdownxField(blank=True, help_text=_('Extra build notes')) @transaction.atomic def cancelBuild(self, user): diff --git a/InvenTree/build/templates/build/detail.html b/InvenTree/build/templates/build/detail.html index 744ed56582..3c3be79b56 100644 --- a/InvenTree/build/templates/build/detail.html +++ b/InvenTree/build/templates/build/detail.html @@ -1,74 +1,67 @@ {% extends "build/build_base.html" %} {% load static %} - +{% load i18n %} {% block details %} {% include "build/tabs.html" with tab='details' %} -

Build Details

+

{% trans "Build Details" %}


- + - + - + - + - + {% if build.batch %} - + {% endif %} {% if build.URL %} - + {% endif %} - + {% if build.is_active %} - + {% endif %} {% if build.completion_date %} - + {% endif %}
Title{{ build.title }}{% trans "Title" %}{{ build.title }}
Part{{ build.part.full_name }}{% trans "Part" %}{{ build.part.full_name }}
Quantity{{ build.quantity }}{% trans "Quantity" %}{{ build.quantity }}
Stock Source{% trans "Stock Source" %} {% if build.take_from %} {{ build.take_from }} {% else %} - Stock can be taken from any available location. + {% trans "Stock can be taken from any available location." %} {% endif %}
Status{% include "build_status.html" with build=build %}{% trans "Status" %}{% include "build_status.html" with build=build %}
Batch{{ build.batch }}{% trans "Batch" %}{{ build.batch }}
URL{{ build.URL }}{% trans "URL" %}{{ build.URL }}
Created{{ build.creation_date }}{% trans "Created" %}{{ build.creation_date }}
Enough Parts?{% trans "Enough Parts?" %} {% if build.can_build %} - Yes + {% trans "Yes" %} {% else %} - No + {% trans "No" %} {% endif %}
Completed{{ build.completion_date }}{% if build.completed_by %}{{ build.completed_by }}{% endif %}{% trans "Completed" %}{{ build.completion_date }}{% if build.completed_by %}{{ build.completed_by }}{% endif %}
-{% if build.notes %} -
-
Notes
-
{{ build.notes }}
-
-{% endif %} - {% endblock %} diff --git a/InvenTree/build/templates/build/notes.html b/InvenTree/build/templates/build/notes.html new file mode 100644 index 0000000000..6e05a40c95 --- /dev/null +++ b/InvenTree/build/templates/build/notes.html @@ -0,0 +1,56 @@ +{% extends "build/build_base.html" %} + +{% load static %} +{% load i18n %} +{% load markdownify %} + +{% block details %} + +{% include "build/tabs.html" with tab='notes' %} + + +{% if editing %} +

{% trans "Build Notes" %}

+
+
+ {% csrf_token %} + + {{ form }} +
+ + +
+ +{{ form.media }} + +{% else %} + +
+
+

{% trans "Build Notes" %}

+
+
+ +
+
+
+
+
+ {{ build.notes | markdownify }} +
+
+{% endif %} + +{% endblock %} + +{% block js_ready %} +{{ block.super }} + +{% if editing %} +{% else %} +$("#edit-notes").click(function() { + location.href = "{% url 'build-notes' build.id %}?edit=1"; +}); +{% endif %} + +{% endblock %} \ No newline at end of file diff --git a/InvenTree/build/templates/build/tabs.html b/InvenTree/build/templates/build/tabs.html index 6f8ba4f355..e9f63cc05b 100644 --- a/InvenTree/build/templates/build/tabs.html +++ b/InvenTree/build/templates/build/tabs.html @@ -1,8 +1,13 @@ +{% load i18n %} + \ No newline at end of file diff --git a/InvenTree/build/urls.py b/InvenTree/build/urls.py index 54f9f60983..6fa7a3c304 100644 --- a/InvenTree/build/urls.py +++ b/InvenTree/build/urls.py @@ -25,6 +25,7 @@ build_detail_urls = [ url(r'^auto-allocate/?', views.BuildAutoAllocate.as_view(), name='build-auto-allocate'), url(r'^unallocate/', views.BuildUnallocate.as_view(), name='build-unallocate'), + url(r'^notes/', views.BuildNotes.as_view(), name='build-notes'), url(r'^.*$', views.BuildDetail.as_view(), name='build-detail'), ] diff --git a/InvenTree/build/views.py b/InvenTree/build/views.py index 4fa6be696a..6a09a3234e 100644 --- a/InvenTree/build/views.py +++ b/InvenTree/build/views.py @@ -7,8 +7,9 @@ from __future__ import unicode_literals from django.utils.translation import ugettext as _ from django.core.exceptions import ValidationError -from django.views.generic import DetailView, ListView +from django.views.generic import DetailView, ListView, UpdateView from django.forms import HiddenInput +from django.urls import reverse from part.models import Part from .models import Build, BuildItem @@ -309,6 +310,28 @@ class BuildComplete(AjaxUpdateView): } +class BuildNotes(UpdateView): + """ View for editing the 'notes' field of a Build object. + """ + + context_object_name = 'build' + template_name = 'build/notes.html' + model = Build + + fields = ['notes'] + + def get_success_url(self): + return reverse('build-notes', kwargs={'pk': self.get_object().id}) + + def get_context_data(self, **kwargs): + + ctx = super().get_context_data(**kwargs) + + ctx['editing'] = str2bool(self.request.GET.get('edit', '')) + + return ctx + + class BuildDetail(DetailView): """ Detail view of a single Build object. """ model = Build diff --git a/InvenTree/company/forms.py b/InvenTree/company/forms.py index 37cfe69ab2..71b870497a 100644 --- a/InvenTree/company/forms.py +++ b/InvenTree/company/forms.py @@ -27,7 +27,6 @@ class EditCompanyForm(HelperForm): 'contact', 'is_customer', 'is_supplier', - 'notes' ] diff --git a/InvenTree/company/migrations/0010_auto_20200201_1231.py b/InvenTree/company/migrations/0010_auto_20200201_1231.py new file mode 100644 index 0000000000..c5afeae2d1 --- /dev/null +++ b/InvenTree/company/migrations/0010_auto_20200201_1231.py @@ -0,0 +1,19 @@ +# Generated by Django 2.2.9 on 2020-02-01 12:31 + +from django.db import migrations +import markdownx.models + + +class Migration(migrations.Migration): + + dependencies = [ + ('company', '0009_auto_20191118_2323'), + ] + + operations = [ + migrations.AlterField( + model_name='company', + name='notes', + field=markdownx.models.MarkdownxField(blank=True), + ), + ] diff --git a/InvenTree/company/models.py b/InvenTree/company/models.py index c072abab1c..a5e56f99fb 100644 --- a/InvenTree/company/models.py +++ b/InvenTree/company/models.py @@ -10,6 +10,7 @@ import os import math from decimal import Decimal +from django.utils.translation import gettext_lazy as _ from django.core.validators import MinValueValidator from django.db import models from django.db.models import Sum @@ -18,6 +19,8 @@ from django.apps import apps from django.urls import reverse from django.conf import settings +from markdownx.models import MarkdownxField + from InvenTree.fields import InvenTreeURLField from InvenTree.status_codes import OrderStatus from common.models import Currency @@ -68,32 +71,32 @@ class Company(models.Model): """ name = models.CharField(max_length=100, blank=False, unique=True, - help_text='Company name') + help_text=_('Company name')) - description = models.CharField(max_length=500, help_text='Description of the company') + description = models.CharField(max_length=500, help_text=_('Description of the company')) - website = models.URLField(blank=True, help_text='Company website URL') + website = models.URLField(blank=True, help_text=_('Company website URL')) address = models.CharField(max_length=200, - blank=True, help_text='Company address') + blank=True, help_text=_('Company address')) phone = models.CharField(max_length=50, - blank=True, help_text='Contact phone number') + blank=True, help_text=_('Contact phone number')) - email = models.EmailField(blank=True, help_text='Contact email address') + email = models.EmailField(blank=True, help_text=_('Contact email address')) contact = models.CharField(max_length=100, - blank=True, help_text='Point of contact') + blank=True, help_text=_('Point of contact')) - URL = InvenTreeURLField(blank=True, help_text='Link to external company information') + URL = InvenTreeURLField(blank=True, help_text=_('Link to external company information')) image = models.ImageField(upload_to=rename_company_image, max_length=255, null=True, blank=True) - notes = models.TextField(blank=True) + notes = MarkdownxField(blank=True) - is_customer = models.BooleanField(default=False, help_text='Do you sell items to this company?') + is_customer = models.BooleanField(default=False, help_text=_('Do you sell items to this company?')) - is_supplier = models.BooleanField(default=True, help_text='Do you purchase items from this company?') + is_supplier = models.BooleanField(default=True, help_text=_('Do you purchase items from this company?')) def __str__(self): """ Get string representation of a Company """ @@ -223,32 +226,32 @@ class SupplierPart(models.Model): 'purchaseable': True, 'is_template': False, }, - help_text='Select part', + help_text=_('Select part'), ) supplier = models.ForeignKey(Company, on_delete=models.CASCADE, related_name='parts', limit_choices_to={'is_supplier': True}, - help_text='Select supplier', + help_text=_('Select supplier'), ) - SKU = models.CharField(max_length=100, help_text='Supplier stock keeping unit') + SKU = models.CharField(max_length=100, help_text=_('Supplier stock keeping unit')) - manufacturer = models.CharField(max_length=100, blank=True, help_text='Manufacturer') + manufacturer = models.CharField(max_length=100, blank=True, help_text=_('Manufacturer')) - MPN = models.CharField(max_length=100, blank=True, help_text='Manufacturer part number') + MPN = models.CharField(max_length=100, blank=True, help_text=_('Manufacturer part number')) - URL = InvenTreeURLField(blank=True, help_text='URL for external supplier part link') + URL = InvenTreeURLField(blank=True, help_text=_('URL for external supplier part link')) - description = models.CharField(max_length=250, blank=True, help_text='Supplier part description') + description = models.CharField(max_length=250, blank=True, help_text=_('Supplier part description')) - note = models.CharField(max_length=100, blank=True, help_text='Notes') + note = models.CharField(max_length=100, blank=True, help_text=_('Notes')) - base_cost = models.DecimalField(max_digits=10, decimal_places=3, default=0, validators=[MinValueValidator(0)], help_text='Minimum charge (e.g. stocking fee)') + base_cost = models.DecimalField(max_digits=10, decimal_places=3, default=0, validators=[MinValueValidator(0)], help_text=_('Minimum charge (e.g. stocking fee)')) - packaging = models.CharField(max_length=50, blank=True, help_text='Part packaging') + packaging = models.CharField(max_length=50, blank=True, help_text=_('Part packaging')) - multiple = models.PositiveIntegerField(default=1, validators=[MinValueValidator(1)], help_text='Order multiple') + multiple = models.PositiveIntegerField(default=1, validators=[MinValueValidator(1)], help_text=('Order multiple')) # TODO - Reimplement lead-time as a charfield with special validation (pattern matching). # lead_time = models.DurationField(blank=True, null=True) diff --git a/InvenTree/company/templates/company/detail.html b/InvenTree/company/templates/company/detail.html index 52a0ec6b78..872d7f675e 100644 --- a/InvenTree/company/templates/company/detail.html +++ b/InvenTree/company/templates/company/detail.html @@ -18,13 +18,6 @@ -{% if company.notes %} -
-
Notes
-
{{ company.notes }}
-
-{% endif %} - {% endblock %} {% block js_ready %} {{ block.super }} diff --git a/InvenTree/company/templates/company/notes.html b/InvenTree/company/templates/company/notes.html new file mode 100644 index 0000000000..467bf49d2d --- /dev/null +++ b/InvenTree/company/templates/company/notes.html @@ -0,0 +1,53 @@ +{% extends "company/company_base.html" %} +{% load static %} +{% load i18n %} +{% block details %} +{% load markdownify %} + +{% include 'company/tabs.html' with tab='notes' %} + +{% if editing %} +

{% trans "Company Notes" %}

+
+
+ {% csrf_token %} + + {{ form }} +
+ + +
+ +{{ form.media }} + +{% else %} + +
+
+

{% trans "Company Notes" %}

+
+
+ +
+
+
+
+
+ {{ company.notes | markdownify }} +
+
+{% endif %} + +{% endblock %} + +{% block js_ready %} +{{ block.super }} + +{% if editing %} +{% else %} +$("#edit-notes").click(function() { + location.href = "{% url 'company-notes' company.id %}?edit=1"; +}); +{% endif %} + +{% endblock %} \ No newline at end of file diff --git a/InvenTree/company/templates/company/tabs.html b/InvenTree/company/templates/company/tabs.html index e52f22fab2..007d9e2e54 100644 --- a/InvenTree/company/templates/company/tabs.html +++ b/InvenTree/company/templates/company/tabs.html @@ -1,23 +1,28 @@ +{% load i18n %} + diff --git a/InvenTree/company/urls.py b/InvenTree/company/urls.py index 55575eb65d..a7683b7bbc 100644 --- a/InvenTree/company/urls.py +++ b/InvenTree/company/urls.py @@ -18,6 +18,7 @@ company_detail_urls = [ url(r'parts/?', views.CompanyDetail.as_view(template_name='company/detail_part.html'), name='company-detail-parts'), url(r'stock/?', views.CompanyDetail.as_view(template_name='company/detail_stock.html'), name='company-detail-stock'), url(r'purchase-orders/?', views.CompanyDetail.as_view(template_name='company/detail_purchase_orders.html'), name='company-detail-purchase-orders'), + url(r'notes/?', views.CompanyNotes.as_view(), name='company-notes'), url(r'thumbnail/?', views.CompanyImage.as_view(), name='company-image'), diff --git a/InvenTree/company/views.py b/InvenTree/company/views.py index 921b49aba2..0fa7a2c712 100644 --- a/InvenTree/company/views.py +++ b/InvenTree/company/views.py @@ -6,8 +6,9 @@ Django views for interacting with Company app # -*- coding: utf-8 -*- from __future__ import unicode_literals -from django.views.generic import DetailView, ListView +from django.views.generic import DetailView, ListView, UpdateView +from django.urls import reverse from django.forms import HiddenInput from InvenTree.views import AjaxCreateView, AjaxUpdateView, AjaxDeleteView @@ -52,6 +53,28 @@ class CompanyIndex(ListView): return queryset +class CompanyNotes(UpdateView): + """ View for editing the 'notes' field of a Company object. + """ + + context_object_name = 'company' + template_name = 'company/notes.html' + model = Company + + fields = ['notes'] + + def get_success_url(self): + return reverse('company-notes', kwargs={'pk': self.get_object().id}) + + def get_context_data(self, **kwargs): + + ctx = super().get_context_data(**kwargs) + + ctx['editing'] = str2bool(self.request.GET.get('edit', '')) + + return ctx + + class CompanyDetail(DetailView): """ Detail view for Company object """ context_obect_name = 'company' diff --git a/InvenTree/locale/de/LC_MESSAGES/django.po b/InvenTree/locale/de/LC_MESSAGES/django.po index 0bf8f61634..569371c780 100644 --- a/InvenTree/locale/de/LC_MESSAGES/django.po +++ b/InvenTree/locale/de/LC_MESSAGES/django.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-01-05 22:23+0000\n" +"POT-Creation-Date: 2020-02-02 01:39+0000\n" "PO-Revision-Date: 2019-12-19 17:48+0100\n" "Last-Translator: \n" "Language-Team: \n" @@ -18,7 +18,7 @@ msgstr "" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Poedit 2.2.4\n" -#: InvenTree/helpers.py:186 order/models.py:159 order/models.py:210 +#: InvenTree/helpers.py:186 order/models.py:161 order/models.py:212 msgid "Invalid quantity provided" msgstr "Keine gültige Menge" @@ -48,19 +48,19 @@ msgstr "" "Anzahl der eindeutigen Seriennummern ({s}) muss mit der Anzahl ({q}) " "übereinstimmen" -#: InvenTree/settings.py:235 +#: InvenTree/settings.py:270 msgid "English" msgstr "Englisch" -#: InvenTree/settings.py:236 +#: InvenTree/settings.py:271 msgid "German" msgstr "Deutsch" -#: InvenTree/settings.py:237 +#: InvenTree/settings.py:272 msgid "French" msgstr "Französisch" -#: InvenTree/settings.py:238 +#: InvenTree/settings.py:273 msgid "Polish" msgstr "Polnisch" @@ -131,27 +131,27 @@ msgstr "Überschuss darf 100% nicht überschreiten" msgid "Overage must be an integer value or a percentage" msgstr "Überschuss muss eine Ganzzahl oder ein Prozentwert sein" -#: build/forms.py:36 +#: build/forms.py:35 msgid "Confirm" msgstr "Bestätigen" -#: build/forms.py:53 stock/forms.py:34 +#: build/forms.py:52 stock/forms.py:34 msgid "Enter unique serial numbers (or leave blank)" msgstr "Eindeutige Seriennummern eingeben (oder leer lassen)" -#: build/forms.py:55 +#: build/forms.py:54 msgid "Confirm build completion" msgstr "Bau-Fertigstellung bestätigen" -#: build/models.py:51 +#: build/models.py:53 msgid "Brief description of the build" msgstr "Kurze Beschreibung des Baus" -#: build/models.py:60 +#: build/models.py:62 msgid "Select part to build" msgstr "Teil für den Bau wählen" -#: build/models.py:66 +#: build/models.py:68 msgid "" "Select location to take stock from for this build (leave blank to take from " "any stock location)" @@ -159,46 +159,46 @@ msgstr "" "Lager-Entnahmestandort für diesen Bau wählen (oder leer lassen für einen " "beliebigen Lager-Standort)" -#: build/models.py:72 +#: build/models.py:74 msgid "Number of parts to build" msgstr "Anzahl der zu bauenden Teile" -#: build/models.py:78 +#: build/models.py:80 msgid "Build status" msgstr "Bau-Status" -#: build/models.py:81 +#: build/models.py:83 msgid "Batch code for this build output" msgstr "Chargennummer für diese Bau-Ausgabe" -#: build/models.py:93 +#: build/models.py:95 msgid "Link to external URL" msgstr "Link zu einer externen URL" -#: build/models.py:95 +#: build/models.py:97 msgid "Extra build notes" msgstr "Notizen für den Bau" -#: build/models.py:380 +#: build/models.py:382 #, python-brace-format msgid "Selected stock item not found in BOM for part '{p}'" msgstr "Ausgewähltes Lagerobjekt nicht in BOM für Teil '{p}' gefunden" -#: build/models.py:383 +#: build/models.py:385 #, python-brace-format msgid "Allocated quantity ({n}) must not exceed available quantity ({q})" msgstr "" "zugewiesene Anzahl ({n}) darf nicht die verfügbare ({q}) Anzahl überschreiten" -#: build/models.py:401 +#: build/models.py:403 msgid "Build to allocate parts" msgstr "Bau starten um Teile zuzuweisen" -#: build/models.py:408 +#: build/models.py:410 msgid "Stock Item to allocate to build" msgstr "Lagerobjekt dem Bau zuweisen" -#: build/models.py:416 +#: build/models.py:418 #, fuzzy msgid "Stock quantity to allocate to build" msgstr "Lagerobjekt-Anzahl dem Bau zuweisen" @@ -217,7 +217,8 @@ msgstr "Zuweisung aufheben" #: build/templates/build/allocate_edit.html:19 #: build/templates/build/allocate_view.html:17 -#: order/templates/order/purchase_order_detail.html:107 +#: build/templates/build/detail.html:17 +#: order/templates/order/purchase_order_detail.html:25 msgid "Part" msgstr "Teil" @@ -244,7 +245,7 @@ msgid "Order Parts" msgstr "Teile bestellen" #: build/templates/build/allocate_view.html:18 -#: order/templates/order/purchase_order_detail.html:108 +#: order/templates/order/purchase_order_detail.html:26 #: part/templates/part/detail.html:33 msgid "Description" msgstr "Beschreibung" @@ -254,7 +255,110 @@ msgstr "Beschreibung" msgid "On Order" msgstr "bestellt" -#: build/views.py:289 stock/views.py:863 +#: build/templates/build/detail.html:8 +#, fuzzy +#| msgid "Build status" +msgid "Build Details" +msgstr "Bau-Status" + +#: build/templates/build/detail.html:14 +msgid "Title" +msgstr "" + +#: build/templates/build/detail.html:20 +#: order/templates/order/purchase_order_detail.html:29 +#: stock/templates/stock/item_base.html:90 +#: stock/templates/stock/stock_adjust.html:18 +msgid "Quantity" +msgstr "Anzahl" + +#: build/templates/build/detail.html:23 +#, fuzzy +#| msgid "Stock Item" +msgid "Stock Source" +msgstr "Lagerobjekt" + +#: build/templates/build/detail.html:28 +msgid "Stock can be taken from any available location." +msgstr "" + +#: build/templates/build/detail.html:33 +#: order/templates/order/order_base.html:71 +#: stock/templates/stock/item_base.html:147 +msgid "Status" +msgstr "Status" + +#: build/templates/build/detail.html:37 stock/templates/stock/item_base.html:96 +msgid "Batch" +msgstr "Los" + +#: build/templates/build/detail.html:42 part/templates/part/detail.html:50 +#: part/templates/part/part_base.html:91 +#: stock/templates/stock/item_base.html:120 +msgid "URL" +msgstr "URL" + +#: build/templates/build/detail.html:46 +#: order/templates/order/order_base.html:75 +msgid "Created" +msgstr "Erstellt" + +#: build/templates/build/detail.html:50 +msgid "Enough Parts?" +msgstr "" + +#: build/templates/build/detail.html:53 +msgid "Yes" +msgstr "" + +#: build/templates/build/detail.html:55 +#, fuzzy +#| msgid "Note" +msgid "No" +msgstr "Notiz" + +#: build/templates/build/detail.html:62 +#, fuzzy +#| msgid "Complete" +msgid "Completed" +msgstr "Fertig" + +#: build/templates/build/notes.html:13 build/templates/build/notes.html:30 +#, fuzzy +#| msgid "Build status" +msgid "Build Notes" +msgstr "Bau-Status" + +#: build/templates/build/notes.html:20 company/templates/company/notes.html:17 +#: order/templates/order/order_notes.html:21 part/templates/part/notes.html:20 +#: stock/templates/stock/item_notes.html:21 +msgid "Save" +msgstr "" + +#: build/templates/build/notes.html:33 company/templates/company/notes.html:30 +#: order/templates/order/order_notes.html:32 part/templates/part/notes.html:32 +#: stock/templates/stock/item_notes.html:32 +#, fuzzy +#| msgid "Entry notes" +msgid "Edit notes" +msgstr "Eintrags-Notizen" + +#: build/templates/build/tabs.html:5 company/templates/company/tabs.html:5 +#: part/templates/part/tabs.html:6 +msgid "Details" +msgstr "Details" + +#: build/templates/build/tabs.html:8 company/models.py:248 +#: company/templates/company/tabs.html:26 order/templates/order/tabs.html:8 +#: part/templates/part/tabs.html:58 stock/templates/stock/tabs.html:8 +msgid "Notes" +msgstr "Notizen" + +#: build/templates/build/tabs.html:11 +msgid "Assign Parts" +msgstr "" + +#: build/views.py:290 stock/views.py:884 #, python-brace-format msgid "The following serial numbers already exist: ({sn})" msgstr "Die folgende Seriennummer existiert bereits: ({sn})" @@ -297,11 +401,136 @@ msgstr "Währungs-Wert" msgid "Use this currency as the base currency" msgstr "Benutze diese Währung als Basis-Währung" +#: company/models.py:74 +#, fuzzy +#| msgid "Company" +msgid "Company name" +msgstr "Firma" + +#: company/models.py:76 +#, fuzzy +#| msgid "Brief description of the build" +msgid "Description of the company" +msgstr "Kurze Beschreibung des Baus" + +#: company/models.py:78 +msgid "Company website URL" +msgstr "" + +#: company/models.py:81 +#, fuzzy +#| msgid "Company" +msgid "Company address" +msgstr "Firma" + +#: company/models.py:84 +msgid "Contact phone number" +msgstr "" + +#: company/models.py:86 +msgid "Contact email address" +msgstr "" + +#: company/models.py:89 +msgid "Point of contact" +msgstr "" + +#: company/models.py:91 +#, fuzzy +#| msgid "Link to external page for further information" +msgid "Link to external company information" +msgstr "Link auf externe Seite für weitere Informationen" + +#: company/models.py:97 +msgid "Do you sell items to this company?" +msgstr "" + +#: company/models.py:99 +msgid "Do you purchase items from this company?" +msgstr "" + +#: company/models.py:229 +#, fuzzy +#| msgid "Select a part" +msgid "Select part" +msgstr "Teil auswählen" + +#: company/models.py:235 +#, fuzzy +#| msgid "Default Supplier" +msgid "Select supplier" +msgstr "Standard-Zulieferer" + +#: company/models.py:238 +#, fuzzy +#| msgid "Stock keeping units for this part" +msgid "Supplier stock keeping unit" +msgstr "Stock Keeping Units (SKU) für dieses Teil" + +#: company/models.py:240 +msgid "Manufacturer" +msgstr "" + +#: company/models.py:242 +#, fuzzy +#| msgid "Internal Part Number" +msgid "Manufacturer part number" +msgstr "Interne Teilenummer" + +#: company/models.py:244 +#, fuzzy +#| msgid "Default supplier part" +msgid "URL for external supplier part link" +msgstr "Standard-Zulieferer?" + +#: company/models.py:246 +#, fuzzy +#| msgid "Part description" +msgid "Supplier part description" +msgstr "Beschreibung des Teils" + +#: company/models.py:250 +#, fuzzy +#| msgid "Minimum allowed stock level" +msgid "Minimum charge (e.g. stocking fee)" +msgstr "Minimal zulässiger Lagerbestand" + +#: company/models.py:252 +msgid "Part packaging" +msgstr "" + +#: company/templates/company/notes.html:10 +#: company/templates/company/notes.html:27 +#, fuzzy +#| msgid "Company" +msgid "Company Notes" +msgstr "Firma" + #: company/templates/company/partdelete.html:5 msgid "Are you sure you want to delete the following Supplier Parts?" msgstr "" "Sind Sie sicher, dass sie die folgenden Zulieferer-Teile löschen möchten?" +#: company/templates/company/tabs.html:9 +#, fuzzy +#| msgid "Supplier Part" +msgid "Supplier Parts" +msgstr "Zulieferer-Teil" + +#: company/templates/company/tabs.html:12 part/templates/part/tabs.html:17 +msgid "Stock" +msgstr "Lagerbestand" + +#: company/templates/company/tabs.html:15 part/templates/part/tabs.html:43 +msgid "Purchase Orders" +msgstr "Bestellungen" + +#: company/templates/company/tabs.html:21 +#, fuzzy +#| msgid "Purchase Orders" +msgid "Sales Orders" +msgstr "Bestellungen" + #: order/forms.py:21 msgid "Place order" msgstr "Bestellung aufgeben" @@ -318,153 +547,162 @@ msgstr "Bestellung stornieren" msgid "Receive parts to this location" msgstr "Teile in diesen Ort empfangen" -#: order/models.py:63 +#: order/models.py:65 msgid "Order reference" msgstr "Bestell-Referenz" -#: order/models.py:65 +#: order/models.py:67 msgid "Order description" msgstr "Bestellungs-Beschreibung" -#: order/models.py:67 +#: order/models.py:69 msgid "Link to external page" msgstr "Link auf externe Seite" -#: order/models.py:84 +#: order/models.py:86 msgid "Order notes" msgstr "Bestell-Notizen" -#: order/models.py:126 +#: order/models.py:128 msgid "Company" msgstr "Firma" -#: order/models.py:157 order/models.py:208 part/views.py:1032 -#: stock/models.py:438 +#: order/models.py:159 order/models.py:210 part/views.py:1065 +#: stock/models.py:440 msgid "Quantity must be greater than zero" msgstr "Anzahl muss größer Null sein" -#: order/models.py:162 +#: order/models.py:164 msgid "Part supplier must match PO supplier" msgstr "Teile-Zulieferer muss dem Zulieferer des Kaufvertrags entsprechen" -#: order/models.py:203 +#: order/models.py:205 msgid "Lines can only be received against an order marked as 'Placed'" msgstr "" -#: order/models.py:252 +#: order/models.py:254 msgid "Item quantity" msgstr "" -#: order/models.py:254 +#: order/models.py:256 msgid "Line item reference" msgstr "Position - Referenz" -#: order/models.py:256 +#: order/models.py:258 msgid "Line item notes" msgstr "Position - Notizen" -#: order/models.py:282 stock/templates/stock/item.html:107 +#: order/models.py:284 stock/templates/stock/item_base.html:108 msgid "Purchase Order" msgstr "Kaufvertrag" -#: order/models.py:291 +#: order/models.py:293 msgid "Supplier part" msgstr "Zulieferer-Teil" -#: order/models.py:294 +#: order/models.py:296 msgid "Number of items received" msgstr "Empfangene Objekt-Anzahl" -#: order/templates/order/purchase_order_detail.html:63 +#: order/templates/order/order_base.html:64 msgid "Purchase Order Details" msgstr "Bestelldetails" -#: order/templates/order/purchase_order_detail.html:66 -#: stock/templates/stock/item.html:125 +#: order/templates/order/order_base.html:67 +#: stock/templates/stock/item_base.html:126 msgid "Supplier" msgstr "Zulieferer" -#: order/templates/order/purchase_order_detail.html:70 -#: stock/templates/stock/item.html:146 -msgid "Status" -msgstr "Status" - -#: order/templates/order/purchase_order_detail.html:74 -msgid "Created" -msgstr "Erstellt" - -#: order/templates/order/purchase_order_detail.html:79 +#: order/templates/order/order_base.html:80 msgid "Issued" msgstr "Aufgegeben" -#: order/templates/order/purchase_order_detail.html:85 -#: order/templates/order/purchase_order_detail.html:113 +#: order/templates/order/order_base.html:86 +#: order/templates/order/purchase_order_detail.html:31 msgid "Received" msgstr "Empfangen" -#: order/templates/order/purchase_order_detail.html:106 +#: order/templates/order/order_notes.html:13 +#: order/templates/order/order_notes.html:29 +#, fuzzy +#| msgid "Order notes" +msgid "Order Notes" +msgstr "Bestell-Notizen" + +#: order/templates/order/purchase_order_detail.html:15 +#, fuzzy +#| msgid "Add Stock Items" +msgid "Add Line Item" +msgstr "Lagerobjekte hinzufügen" + +#: order/templates/order/purchase_order_detail.html:19 +#, fuzzy +#| msgid "Order notes" +msgid "Order Items" +msgstr "Bestell-Notizen" + +#: order/templates/order/purchase_order_detail.html:24 msgid "Line" msgstr "Position" -#: order/templates/order/purchase_order_detail.html:109 +#: order/templates/order/purchase_order_detail.html:27 msgid "Order Code" msgstr "Bestellnummer" -#: order/templates/order/purchase_order_detail.html:110 +#: order/templates/order/purchase_order_detail.html:28 msgid "Reference" msgstr "Referenz" -#: order/templates/order/purchase_order_detail.html:111 -#: stock/templates/stock/item.html:89 -#: stock/templates/stock/stock_adjust.html:18 -msgid "Quantity" -msgstr "Anzahl" - -#: order/templates/order/purchase_order_detail.html:115 +#: order/templates/order/purchase_order_detail.html:33 msgid "Note" msgstr "Notiz" -#: order/templates/order/purchase_order_detail.html:168 -#: part/templates/part/detail.html:152 stock/templates/stock/item.html:151 -msgid "Notes" -msgstr "Notizen" +#: order/templates/order/tabs.html:5 +#, fuzzy +#| msgid "Stock Items" +msgid "Items" +msgstr "Lagerobjekte" -#: order/views.py:141 +#: order/views.py:164 msgid "Confirm order cancellation" msgstr "Bestell-Stornierung bestätigen" -#: order/views.py:174 +#: order/views.py:197 msgid "Confirm order placement" msgstr "Bestellungstätigung bestätigen" -#: order/views.py:328 +#: order/views.py:351 #, fuzzy #| msgid "Number of items received" msgid "Items received" msgstr "Empfangene Objekt-Anzahl" -#: order/views.py:342 +#: order/views.py:365 msgid "No destination set" msgstr "" -#: order/views.py:373 +#: order/views.py:396 msgid "Error converting quantity to number" msgstr "" -#: order/views.py:379 +#: order/views.py:402 msgid "Receive quantity less than zero" msgstr "" -#: order/views.py:740 +#: order/views.py:408 +msgid "No lines specified" +msgstr "" + +#: order/views.py:767 msgid "Invalid Purchase Order" msgstr "Ungültige Bestellung" -#: order/views.py:748 +#: order/views.py:775 #, fuzzy msgid "Supplier must match for Part and Order" msgstr "Zulieferer muss zum Teil und zur Bestellung passen" -#: order/views.py:753 +#: order/views.py:780 msgid "Invalid SupplierPart selection" msgstr "Ungültige Wahl des Zulieferer-Teils" @@ -503,189 +741,227 @@ msgstr "" msgid "Confirm part creation" msgstr "Erstellen des Teils bestätigen" -#: part/forms.py:173 +#: part/forms.py:172 msgid "Input quantity for price calculation" msgstr "Eintragsmenge zur Preisberechnung" -#: part/forms.py:176 +#: part/forms.py:175 msgid "Select currency for price calculation" msgstr "Währung zur Preisberechnung wählen" -#: part/models.py:55 +#: part/models.py:57 msgid "Default location for parts in this category" msgstr "Standard-Standort für Teile dieser Kategorie" -#: part/models.py:58 +#: part/models.py:60 msgid "Default keywords for parts in this category" msgstr "Standard-Stichworte für Teile dieser Kategorie" -#: part/models.py:307 +#: part/models.py:309 msgid "Part must be unique for name, IPN and revision" msgstr "Namen, Teile- und Revisionsnummern müssen eindeutig sein" -#: part/models.py:321 +#: part/models.py:323 msgid "Part cannot be a template part if it is a variant of another part" msgstr "Teil kann keine Vorlage sein wenn es Variante eines anderen Teils ist" -#: part/models.py:322 +#: part/models.py:324 msgid "Part cannot be a variant of another part if it is already a template" msgstr "" "Teil kann keine Variante eines anderen Teils sein wenn es bereits eine " "Vorlage ist" -#: part/models.py:326 part/templates/part/detail.html:17 +#: part/models.py:328 part/templates/part/detail.html:17 msgid "Part name" msgstr "Name des Teils" -#: part/models.py:330 +#: part/models.py:332 msgid "Is this part a template part?" msgstr "Ist dieses Teil eine Vorlage?" -#: part/models.py:339 +#: part/models.py:341 msgid "Is this part a variant of another part?" msgstr "Ist dieses Teil eine Variante eines anderen Teils?" -#: part/models.py:341 +#: part/models.py:343 msgid "Part description" msgstr "Beschreibung des Teils" -#: part/models.py:343 +#: part/models.py:345 msgid "Part keywords to improve visibility in search results" msgstr "Schlüsselworte um die Sichtbarkeit in Suchergebnissen zu verbessern" -#: part/models.py:348 +#: part/models.py:350 msgid "Part category" msgstr "Teile-Kategorie" -#: part/models.py:350 +#: part/models.py:352 msgid "Internal Part Number" msgstr "Interne Teilenummer" -#: part/models.py:352 +#: part/models.py:354 msgid "Part revision or version number" msgstr "Revisions- oder Versionsnummer" -#: part/models.py:354 +#: part/models.py:356 msgid "Link to extenal URL" msgstr "Link zu einer Externen URL" -#: part/models.py:360 +#: part/models.py:362 msgid "Where is this item normally stored?" msgstr "Wo wird dieses Teil normalerweise gelagert?" -#: part/models.py:404 +#: part/models.py:406 msgid "Default supplier part" msgstr "Standard-Zulieferer?" -#: part/models.py:407 +#: part/models.py:409 msgid "Minimum allowed stock level" msgstr "Minimal zulässiger Lagerbestand" -#: part/models.py:409 +#: part/models.py:411 msgid "Stock keeping units for this part" msgstr "Stock Keeping Units (SKU) für dieses Teil" -#: part/models.py:411 +#: part/models.py:413 msgid "Can this part be built from other parts?" msgstr "Kann dieses Teil aus anderen Teilen angefertigt werden?" -#: part/models.py:413 +#: part/models.py:415 msgid "Can this part be used to build other parts?" msgstr "Kann dieses Teil zum Bau von anderen genutzt werden?" -#: part/models.py:415 +#: part/models.py:417 msgid "Does this part have tracking for unique items?" msgstr "Hat dieses Teil Tracking für einzelne Objekte?" -#: part/models.py:417 +#: part/models.py:419 msgid "Can this part be purchased from external suppliers?" msgstr "Kann dieses Teil von externen Zulieferern gekauft werden?" -#: part/models.py:419 +#: part/models.py:421 msgid "Can this part be sold to customers?" msgstr "Kann dieses Teil an Kunden verkauft werden?" -#: part/models.py:421 +#: part/models.py:423 msgid "Is this part active?" msgstr "Ist dieses Teil aktiv?" -#: part/models.py:423 +#: part/models.py:425 msgid "Is this a virtual part, such as a software product or license?" msgstr "Ist dieses Teil virtuell, wie zum Beispiel eine Software oder Lizenz?" #: part/models.py:427 +msgid "Part notes - supports Markdown formatting" +msgstr "" + +#: part/models.py:429 msgid "Stored BOM checksum" msgstr "Prüfsumme der Stückliste gespeichert" -#: part/models.py:934 +#: part/models.py:936 msgid "Select file to attach" msgstr "Datei zum Anhängen auswählen" -#: part/models.py:936 +#: part/models.py:938 msgid "File comment" msgstr "Datei-Kommentar" -#: part/models.py:991 +#: part/models.py:993 msgid "Parameter template name must be unique" msgstr "Vorlagen-Name des Parameters muss eindeutig sein" -#: part/models.py:996 +#: part/models.py:998 msgid "Parameter Name" msgstr "Name des Parameters" -#: part/models.py:998 +#: part/models.py:1000 msgid "Parameter Units" msgstr "Parameter Einheit" -#: part/models.py:1024 +#: part/models.py:1026 msgid "Parent Part" msgstr "Ausgangsteil" -#: part/models.py:1026 +#: part/models.py:1028 msgid "Parameter Template" msgstr "Parameter Vorlage" -#: part/models.py:1028 +#: part/models.py:1030 msgid "Parameter Value" msgstr "Parameter Wert" -#: part/models.py:1052 +#: part/models.py:1054 msgid "Select parent part" msgstr "Ausgangsteil auswählen" -#: part/models.py:1060 +#: part/models.py:1062 msgid "Select part to be used in BOM" msgstr "Teil für die Nutzung in der Stückliste auswählen" -#: part/models.py:1066 +#: part/models.py:1068 msgid "BOM quantity for this BOM item" msgstr "Stücklisten-Anzahl für dieses Stücklisten-Teil" -#: part/models.py:1069 +#: part/models.py:1071 msgid "Estimated build wastage quantity (absolute or percentage)" msgstr "Geschätzter Ausschuss (absolut oder prozentual)" -#: part/models.py:1072 +#: part/models.py:1074 msgid "BOM item reference" msgstr "Referenz des Objekts auf der Stückliste" -#: part/models.py:1075 +#: part/models.py:1077 msgid "BOM item notes" msgstr "Notizen zum Stücklisten-Objekt" -#: part/models.py:1077 +#: part/models.py:1079 msgid "BOM line checksum" msgstr "Prüfsumme der Stückliste" -#: part/models.py:1140 +#: part/models.py:1142 msgid "Part cannot be added to its own Bill of Materials" msgstr "Teil kann nicht zu seiner eigenen Stückliste hinzugefügt werden" -#: part/models.py:1147 +#: part/models.py:1149 #, python-brace-format msgid "Part '{p1}' is used in BOM for '{p2}' (recursive)" msgstr "Teil '{p1}' wird in Stückliste für Teil '{p2}' benutzt (rekursiv)" +#: part/templates/part/attachments.html:8 +#, fuzzy +#| msgid "Attachments" +msgid "Part Attachments" +msgstr "Anhänge" + +#: part/templates/part/attachments.html:14 +#, fuzzy +#| msgid "Attachments" +msgid "Add Attachment" +msgstr "Anhänge" + +#: part/templates/part/attachments.html:22 +msgid "File" +msgstr "" + +#: part/templates/part/attachments.html:23 +#, fuzzy +#| msgid "File comment" +msgid "Comment" +msgstr "Datei-Kommentar" + +#: part/templates/part/attachments.html:34 +#, fuzzy +#| msgid "Attachments" +msgid "Edit attachment" +msgstr "Anhänge" + +#: part/templates/part/attachments.html:37 +#, fuzzy +#| msgid "Attachments" +msgid "Delete attachment" +msgstr "Anhänge" + #: part/templates/part/category.html:13 part/templates/part/category.html:69 msgid "Part Categories" msgstr "Teile-Kategorien" @@ -742,11 +1018,6 @@ msgstr "Revision" msgid "Variant Of" msgstr "Variante von" -#: part/templates/part/detail.html:50 part/templates/part/part_base.html:91 -#: stock/templates/stock/item.html:119 -msgid "URL" -msgstr "URL" - #: part/templates/part/detail.html:55 msgid "Category" msgstr "Kategorie" @@ -831,6 +1102,12 @@ msgstr "Teil kann an Kunden verkauft werden" msgid "Part cannot be sold to customers" msgstr "Teil kann nicht an Kunden verkauft werden" +#: part/templates/part/notes.html:13 part/templates/part/notes.html:29 +#, fuzzy +#| msgid "Notes" +msgid "Part Notes" +msgstr "Notizen" + #: part/templates/part/part_base.html:11 msgid "This part is not active" msgstr "Dieses Teil ist nicht aktiv" @@ -863,10 +1140,6 @@ msgstr "Herstellbar?" msgid "Underway" msgstr "unterwegs" -#: part/templates/part/tabs.html:6 -msgid "Details" -msgstr "Details" - #: part/templates/part/tabs.html:9 msgid "Parameters" msgstr "Parameter" @@ -875,15 +1148,11 @@ msgstr "Parameter" msgid "Variants" msgstr "Varianten" -#: part/templates/part/tabs.html:17 -msgid "Stock" -msgstr "Lagerbestand" - #: part/templates/part/tabs.html:26 msgid "BOM" msgstr "Stückliste" -#: part/templates/part/tabs.html:28 stock/templates/stock/item.html:101 +#: part/templates/part/tabs.html:28 stock/templates/stock/item_base.html:102 msgid "Build" msgstr "Bau" @@ -895,11 +1164,7 @@ msgstr "Benutzt in" msgid "Suppliers" msgstr "Zulieferer" -#: part/templates/part/tabs.html:43 -msgid "Purchase Orders" -msgstr "Bestellungen" - -#: part/templates/part/tabs.html:48 +#: part/templates/part/tabs.html:48 stock/templates/stock/tabs.html:5 msgid "Tracking" msgstr "Tracking" @@ -912,27 +1177,27 @@ msgstr "Anhänge" msgid "Set category for {n} parts" msgstr "Kategorie für {n} Teile setzen" -#: part/views.py:773 +#: part/views.py:806 msgid "No BOM file provided" msgstr "Keine Stückliste angegeben" -#: part/views.py:1034 +#: part/views.py:1067 msgid "Enter a valid quantity" msgstr "Bitte eine gültige Anzahl eingeben" -#: part/views.py:1058 part/views.py:1061 +#: part/views.py:1091 part/views.py:1094 msgid "Select valid part" msgstr "Bitte ein gültiges Teil auswählen" -#: part/views.py:1067 +#: part/views.py:1100 msgid "Duplicate part selected" msgstr "Teil doppelt ausgewählt" -#: part/views.py:1095 +#: part/views.py:1128 msgid "Select a part" msgstr "Teil auswählen" -#: part/views.py:1099 +#: part/views.py:1132 msgid "Specify quantity" msgstr "Anzahl angeben" @@ -960,7 +1225,7 @@ msgstr "Bewegung der Lagerobjekte bestätigen" msgid "Set the destination as the default location for selected parts" msgstr "Setze das Ziel als Standard-Ziel für ausgewählte Teile" -#: stock/models.py:202 +#: stock/models.py:204 #, python-brace-format msgid "" "A stock item with this serial number already exists for template part {part}" @@ -968,124 +1233,129 @@ msgstr "" "Ein Teil mit dieser Seriennummer existiert bereits für die Teilevorlage " "{part}" -#: stock/models.py:207 +#: stock/models.py:209 msgid "A stock item with this serial number already exists" msgstr "Ein Teil mit dieser Seriennummer existiert bereits" -#: stock/models.py:226 +#: stock/models.py:228 #, python-brace-format msgid "Part type ('{pf}') must be {pe}" msgstr "Teile-Typ ('{pf}') muss {pe} sein" -#: stock/models.py:236 stock/models.py:245 +#: stock/models.py:238 stock/models.py:247 msgid "Quantity must be 1 for item with a serial number" msgstr "Anzahl muss für Objekte mit Seriennummer \"1\" sein" -#: stock/models.py:237 +#: stock/models.py:239 msgid "Serial number cannot be set if quantity greater than 1" msgstr "" "Seriennummer kann nicht gesetzt werden wenn die Anzahl größer als \"1\" ist" -#: stock/models.py:253 +#: stock/models.py:255 msgid "Stock item cannot be created for a template Part" msgstr "Lagerobjekt kann nicht für Vorlagen-Teile angelegt werden" -#: stock/models.py:262 +#: stock/models.py:264 msgid "Item cannot belong to itself" msgstr "Teil kann nicht zu sich selbst gehören" -#: stock/models.py:298 +#: stock/models.py:300 msgid "Base part" msgstr "Basis-Teil" -#: stock/models.py:305 +#: stock/models.py:307 msgid "Select a matching supplier part for this stock item" msgstr "Passenden Zulieferer für dieses Lagerobjekt auswählen" -#: stock/models.py:309 +#: stock/models.py:311 msgid "Where is this stock item located?" msgstr "Wo wird dieses Teil normalerweise gelagert?" -#: stock/models.py:313 +#: stock/models.py:315 msgid "Is this item installed in another item?" msgstr "Ist dieses Teil in einem anderen verbaut?" -#: stock/models.py:317 +#: stock/models.py:319 msgid "Item assigned to customer?" msgstr "Ist dieses Objekt einem Kunden zugeteilt?" -#: stock/models.py:320 +#: stock/models.py:322 msgid "Serial number for this item" msgstr "Seriennummer für dieses Teil" -#: stock/models.py:325 +#: stock/models.py:327 msgid "Batch code for this stock item" msgstr "Losnummer für dieses Lagerobjekt" -#: stock/models.py:334 +#: stock/models.py:336 #, fuzzy msgid "Build for this stock item" msgstr "Bau für dieses Lagerobjekt" -#: stock/models.py:343 +#: stock/models.py:345 msgid "Purchase order for this stock item" msgstr "Bestellung für dieses Teil" -#: stock/models.py:354 +#: stock/models.py:356 msgid "Delete this Stock Item when stock is depleted" msgstr "Objekt löschen wenn Lagerbestand aufgebraucht" -#: stock/models.py:361 +#: stock/models.py:363 stock/templates/stock/item_notes.html:13 +#: stock/templates/stock/item_notes.html:29 msgid "Stock Item Notes" msgstr "Lagerobjekt-Notizen" -#: stock/models.py:435 +#: stock/models.py:437 msgid "Quantity must be integer" msgstr "Anzahl muss eine Ganzzahl sein" -#: stock/models.py:441 +#: stock/models.py:443 #, python-brace-format msgid "Quantity must not exceed available stock quantity ({n})" msgstr "Anzahl darf nicht die verfügbare Anzahl überschreiten ({n})" -#: stock/models.py:444 stock/models.py:447 +#: stock/models.py:446 stock/models.py:449 msgid "Serial numbers must be a list of integers" msgstr "Seriennummern muss eine Liste von Ganzzahlen sein" -#: stock/models.py:450 +#: stock/models.py:452 msgid "Quantity does not match serial numbers" msgstr "Anzahl stimmt nicht mit den Seriennummern überein" -#: stock/models.py:460 +#: stock/models.py:462 msgid "Serial numbers already exist: " msgstr "Seriennummern existieren bereits:" -#: stock/models.py:481 +#: stock/models.py:483 msgid "Add serial number" msgstr "Seriennummer hinzufügen" -#: stock/models.py:484 +#: stock/models.py:486 #, python-brace-format msgid "Serialized {n} items" msgstr "{n} Teile serialisiert" -#: stock/models.py:750 +#: stock/models.py:752 msgid "Tracking entry title" msgstr "Name des Eintrags-Trackings" -#: stock/models.py:752 +#: stock/models.py:754 msgid "Entry notes" msgstr "Eintrags-Notizen" -#: stock/models.py:754 +#: stock/models.py:756 msgid "Link to external page for further information" msgstr "Link auf externe Seite für weitere Informationen" -#: stock/templates/stock/item.html:9 +#: stock/templates/stock/item.html:12 +msgid "Stock Tracking Information" +msgstr "Informationen zum Lagerbestands-Tracking" + +#: stock/templates/stock/item_base.html:10 msgid "Stock Item Details" msgstr "Lagerbestands-Details" -#: stock/templates/stock/item.html:52 +#: stock/templates/stock/item_base.html:53 msgid "" "This stock item is serialized - it has a unique serial number and the " "quantity cannot be adjusted." @@ -1093,54 +1363,46 @@ msgstr "" "Dieses Lagerobjekt ist serialisiert. Es hat eine eindeutige Seriennummer und " "die Anzahl kann nicht angepasst werden." -#: stock/templates/stock/item.html:56 +#: stock/templates/stock/item_base.html:57 msgid "" "This stock item will be automatically deleted when all stock is depleted." msgstr "" "Dieses Lagerobjekt wird automatisch gelöscht wenn der Lagerbestand " "aufgebraucht ist." -#: stock/templates/stock/item.html:73 +#: stock/templates/stock/item_base.html:74 msgid "Belongs To" msgstr "Gehört zu" -#: stock/templates/stock/item.html:78 +#: stock/templates/stock/item_base.html:79 #: stock/templates/stock/stock_adjust.html:17 msgid "Location" msgstr "Standort" -#: stock/templates/stock/item.html:84 +#: stock/templates/stock/item_base.html:85 msgid "Serial Number" msgstr "Seriennummer" -#: stock/templates/stock/item.html:95 -msgid "Batch" -msgstr "Los" - -#: stock/templates/stock/item.html:113 +#: stock/templates/stock/item_base.html:114 msgid "Customer" msgstr "Kunde" -#: stock/templates/stock/item.html:129 +#: stock/templates/stock/item_base.html:130 msgid "Supplier Part" msgstr "Zulieferer-Teil" -#: stock/templates/stock/item.html:134 +#: stock/templates/stock/item_base.html:135 msgid "Last Updated" msgstr "Zuletzt aktualisiert" -#: stock/templates/stock/item.html:138 +#: stock/templates/stock/item_base.html:139 msgid "Last Stocktake" msgstr "Letzte Inventur" -#: stock/templates/stock/item.html:142 +#: stock/templates/stock/item_base.html:143 msgid "No stocktake performed" msgstr "Keine Inventur ausgeführt" -#: stock/templates/stock/item.html:160 -msgid "Stock Tracking Information" -msgstr "Informationen zum Lagerbestands-Tracking" - #: stock/templates/stock/location.html:37 msgid "Location Details" msgstr "Standort-Details" @@ -1174,141 +1436,167 @@ msgstr "Lagerobjekt-Standorte" msgid "Stock Item" msgstr "Lagerobjekt" -#: stock/views.py:96 +#: stock/views.py:117 msgid "Edit Stock Location" msgstr "Lagerobjekt-Standort bearbeiten" -#: stock/views.py:120 +#: stock/views.py:141 msgid "Stock Location QR code" msgstr "QR-Code für diesen Standort" -#: stock/views.py:135 +#: stock/views.py:156 #, fuzzy msgid "Stock Export Options" msgstr "Lagerobjekt-Export-Optionen" -#: stock/views.py:243 +#: stock/views.py:264 msgid "Stock Item QR Code" msgstr "Lagerobjekt-QR-Code" -#: stock/views.py:266 +#: stock/views.py:287 msgid "Adjust Stock" msgstr "Lagerbestand anpassen" -#: stock/views.py:375 +#: stock/views.py:396 msgid "Move Stock Items" msgstr "Lagerobjekte bewegen" -#: stock/views.py:376 +#: stock/views.py:397 msgid "Count Stock Items" msgstr "Lagerobjekte zählen" -#: stock/views.py:377 +#: stock/views.py:398 msgid "Remove From Stock" msgstr "Aus Lagerbestand entfernen" -#: stock/views.py:378 +#: stock/views.py:399 msgid "Add Stock Items" msgstr "Lagerobjekte hinzufügen" -#: stock/views.py:379 +#: stock/views.py:400 msgid "Delete Stock Items" msgstr "Lagerobjekte löschen" -#: stock/views.py:407 +#: stock/views.py:428 msgid "Must enter integer value" msgstr "Nur Ganzzahl eingeben" -#: stock/views.py:412 +#: stock/views.py:433 msgid "Quantity must be positive" msgstr "Anzahl muss positiv sein" -#: stock/views.py:419 +#: stock/views.py:440 #, python-brace-format msgid "Quantity must not exceed {x}" msgstr "Anzahl darf {x} nicht überschreiten" -#: stock/views.py:427 +#: stock/views.py:448 msgid "Confirm stock adjustment" msgstr "Bestands-Anpassung bestätigen" -#: stock/views.py:498 +#: stock/views.py:519 #, python-brace-format msgid "Added stock to {n} items" msgstr "Vorrat zu {n} Lagerobjekten hinzugefügt" -#: stock/views.py:513 +#: stock/views.py:534 #, python-brace-format msgid "Removed stock from {n} items" msgstr "Vorrat von {n} Lagerobjekten entfernt" -#: stock/views.py:526 +#: stock/views.py:547 #, python-brace-format msgid "Counted stock for {n} items" msgstr "Bestand für {n} Objekte erfasst" -#: stock/views.py:554 +#: stock/views.py:575 msgid "No items were moved" msgstr "Keine Lagerobjekte wurden bewegt" -#: stock/views.py:557 +#: stock/views.py:578 #, python-brace-format msgid "Moved {n} items to {dest}" msgstr "{n} Teile nach {dest} bewegt" -#: stock/views.py:576 +#: stock/views.py:597 #, python-brace-format msgid "Deleted {n} stock items" msgstr "{n} Teile im Lager gelöscht" -#: stock/views.py:588 +#: stock/views.py:609 msgid "Edit Stock Item" msgstr "Lagerobjekt bearbeiten" -#: stock/views.py:624 +#: stock/views.py:645 msgid "Create new Stock Location" msgstr "Neuen Lager-Standort erstellen" -#: stock/views.py:645 +#: stock/views.py:666 msgid "Serialize Stock" msgstr "Lagerbestand erfassen" -#: stock/views.py:725 +#: stock/views.py:746 msgid "Create new Stock Item" msgstr "Neues Lagerobjekt hinzufügen" -#: stock/views.py:789 +#: stock/views.py:810 msgid "Copy Stock Item" msgstr "Lagerobjekt kopieren" -#: stock/views.py:839 +#: stock/views.py:860 msgid "Invalid quantity" msgstr "Ungültige Menge" -#: stock/views.py:842 +#: stock/views.py:863 msgid "Invalid part selection" msgstr "Ungültige Teileauswahl" -#: stock/views.py:904 +#: stock/views.py:925 msgid "Created new stock item" msgstr "Neues Lagerobjekt erstellt" -#: stock/views.py:921 +#: stock/views.py:942 msgid "Delete Stock Location" msgstr "Standort löschen" -#: stock/views.py:934 +#: stock/views.py:955 msgid "Delete Stock Item" msgstr "Lagerobjekt löschen" -#: stock/views.py:945 +#: stock/views.py:966 msgid "Delete Stock Tracking Entry" msgstr "Lagerbestands-Tracking-Eintrag löschen" -#: stock/views.py:962 +#: stock/views.py:983 msgid "Edit Stock Tracking Entry" msgstr "Lagerbestands-Tracking-Eintrag bearbeiten" -#: stock/views.py:971 +#: stock/views.py:992 msgid "Add Stock Tracking Entry" msgstr "Lagerbestands-Tracking-Eintrag hinzufügen" + +#: templates/about.html:18 +msgid "InvenTree Version Information" +msgstr "" + +#: templates/about.html:21 +#, fuzzy +#| msgid "Revision" +msgid "Version" +msgstr "Revision" + +#: templates/about.html:24 +msgid "Commit Hash" +msgstr "" + +#: templates/about.html:27 +msgid "Commit Date" +msgstr "" + +#: templates/about.html:33 +msgid "InvenTree Documentation" +msgstr "" + +#: templates/about.html:37 +msgid "View Code on GitHub" +msgstr "" diff --git a/InvenTree/locale/en/LC_MESSAGES/django.po b/InvenTree/locale/en/LC_MESSAGES/django.po index 5266643986..634d43140c 100644 --- a/InvenTree/locale/en/LC_MESSAGES/django.po +++ b/InvenTree/locale/en/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-01-05 22:23+0000\n" +"POT-Creation-Date: 2020-02-02 01:39+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -18,7 +18,7 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: InvenTree/helpers.py:186 order/models.py:159 order/models.py:210 +#: InvenTree/helpers.py:186 order/models.py:161 order/models.py:212 msgid "Invalid quantity provided" msgstr "" @@ -46,19 +46,19 @@ msgstr "" msgid "Number of unique serial number ({s}) must match quantity ({q})" msgstr "" -#: InvenTree/settings.py:235 +#: InvenTree/settings.py:270 msgid "English" msgstr "" -#: InvenTree/settings.py:236 +#: InvenTree/settings.py:271 msgid "German" msgstr "" -#: InvenTree/settings.py:237 +#: InvenTree/settings.py:272 msgid "French" msgstr "" -#: InvenTree/settings.py:238 +#: InvenTree/settings.py:273 msgid "Polish" msgstr "" @@ -129,71 +129,71 @@ msgstr "" msgid "Overage must be an integer value or a percentage" msgstr "" -#: build/forms.py:36 +#: build/forms.py:35 msgid "Confirm" msgstr "" -#: build/forms.py:53 stock/forms.py:34 +#: build/forms.py:52 stock/forms.py:34 msgid "Enter unique serial numbers (or leave blank)" msgstr "" -#: build/forms.py:55 +#: build/forms.py:54 msgid "Confirm build completion" msgstr "" -#: build/models.py:51 +#: build/models.py:53 msgid "Brief description of the build" msgstr "" -#: build/models.py:60 +#: build/models.py:62 msgid "Select part to build" msgstr "" -#: build/models.py:66 +#: build/models.py:68 msgid "" "Select location to take stock from for this build (leave blank to take from " "any stock location)" msgstr "" -#: build/models.py:72 +#: build/models.py:74 msgid "Number of parts to build" msgstr "" -#: build/models.py:78 +#: build/models.py:80 msgid "Build status" msgstr "" -#: build/models.py:81 +#: build/models.py:83 msgid "Batch code for this build output" msgstr "" -#: build/models.py:93 +#: build/models.py:95 msgid "Link to external URL" msgstr "" -#: build/models.py:95 +#: build/models.py:97 msgid "Extra build notes" msgstr "" -#: build/models.py:380 +#: build/models.py:382 #, python-brace-format msgid "Selected stock item not found in BOM for part '{p}'" msgstr "" -#: build/models.py:383 +#: build/models.py:385 #, python-brace-format msgid "Allocated quantity ({n}) must not exceed available quantity ({q})" msgstr "" -#: build/models.py:401 +#: build/models.py:403 msgid "Build to allocate parts" msgstr "" -#: build/models.py:408 +#: build/models.py:410 msgid "Stock Item to allocate to build" msgstr "" -#: build/models.py:416 +#: build/models.py:418 msgid "Stock quantity to allocate to build" msgstr "" @@ -211,7 +211,8 @@ msgstr "" #: build/templates/build/allocate_edit.html:19 #: build/templates/build/allocate_view.html:17 -#: order/templates/order/purchase_order_detail.html:107 +#: build/templates/build/detail.html:17 +#: order/templates/order/purchase_order_detail.html:25 msgid "Part" msgstr "" @@ -238,7 +239,7 @@ msgid "Order Parts" msgstr "" #: build/templates/build/allocate_view.html:18 -#: order/templates/order/purchase_order_detail.html:108 +#: order/templates/order/purchase_order_detail.html:26 #: part/templates/part/detail.html:33 msgid "Description" msgstr "" @@ -248,7 +249,98 @@ msgstr "" msgid "On Order" msgstr "" -#: build/views.py:289 stock/views.py:863 +#: build/templates/build/detail.html:8 +msgid "Build Details" +msgstr "" + +#: build/templates/build/detail.html:14 +msgid "Title" +msgstr "" + +#: build/templates/build/detail.html:20 +#: order/templates/order/purchase_order_detail.html:29 +#: stock/templates/stock/item_base.html:90 +#: stock/templates/stock/stock_adjust.html:18 +msgid "Quantity" +msgstr "" + +#: build/templates/build/detail.html:23 +msgid "Stock Source" +msgstr "" + +#: build/templates/build/detail.html:28 +msgid "Stock can be taken from any available location." +msgstr "" + +#: build/templates/build/detail.html:33 +#: order/templates/order/order_base.html:71 +#: stock/templates/stock/item_base.html:147 +msgid "Status" +msgstr "" + +#: build/templates/build/detail.html:37 stock/templates/stock/item_base.html:96 +msgid "Batch" +msgstr "" + +#: build/templates/build/detail.html:42 part/templates/part/detail.html:50 +#: part/templates/part/part_base.html:91 +#: stock/templates/stock/item_base.html:120 +msgid "URL" +msgstr "" + +#: build/templates/build/detail.html:46 +#: order/templates/order/order_base.html:75 +msgid "Created" +msgstr "" + +#: build/templates/build/detail.html:50 +msgid "Enough Parts?" +msgstr "" + +#: build/templates/build/detail.html:53 +msgid "Yes" +msgstr "" + +#: build/templates/build/detail.html:55 +msgid "No" +msgstr "" + +#: build/templates/build/detail.html:62 +msgid "Completed" +msgstr "" + +#: build/templates/build/notes.html:13 build/templates/build/notes.html:30 +msgid "Build Notes" +msgstr "" + +#: build/templates/build/notes.html:20 company/templates/company/notes.html:17 +#: order/templates/order/order_notes.html:21 part/templates/part/notes.html:20 +#: stock/templates/stock/item_notes.html:21 +msgid "Save" +msgstr "" + +#: build/templates/build/notes.html:33 company/templates/company/notes.html:30 +#: order/templates/order/order_notes.html:32 part/templates/part/notes.html:32 +#: stock/templates/stock/item_notes.html:32 +msgid "Edit notes" +msgstr "" + +#: build/templates/build/tabs.html:5 company/templates/company/tabs.html:5 +#: part/templates/part/tabs.html:6 +msgid "Details" +msgstr "" + +#: build/templates/build/tabs.html:8 company/models.py:248 +#: company/templates/company/tabs.html:26 order/templates/order/tabs.html:8 +#: part/templates/part/tabs.html:58 stock/templates/stock/tabs.html:8 +msgid "Notes" +msgstr "" + +#: build/templates/build/tabs.html:11 +msgid "Assign Parts" +msgstr "" + +#: build/views.py:290 stock/views.py:884 #, python-brace-format msgid "The following serial numbers already exist: ({sn})" msgstr "" @@ -289,10 +381,107 @@ msgstr "" msgid "Use this currency as the base currency" msgstr "" +#: company/models.py:74 +msgid "Company name" +msgstr "" + +#: company/models.py:76 +msgid "Description of the company" +msgstr "" + +#: company/models.py:78 +msgid "Company website URL" +msgstr "" + +#: company/models.py:81 +msgid "Company address" +msgstr "" + +#: company/models.py:84 +msgid "Contact phone number" +msgstr "" + +#: company/models.py:86 +msgid "Contact email address" +msgstr "" + +#: company/models.py:89 +msgid "Point of contact" +msgstr "" + +#: company/models.py:91 +msgid "Link to external company information" +msgstr "" + +#: company/models.py:97 +msgid "Do you sell items to this company?" +msgstr "" + +#: company/models.py:99 +msgid "Do you purchase items from this company?" +msgstr "" + +#: company/models.py:229 +msgid "Select part" +msgstr "" + +#: company/models.py:235 +msgid "Select supplier" +msgstr "" + +#: company/models.py:238 +msgid "Supplier stock keeping unit" +msgstr "" + +#: company/models.py:240 +msgid "Manufacturer" +msgstr "" + +#: company/models.py:242 +msgid "Manufacturer part number" +msgstr "" + +#: company/models.py:244 +msgid "URL for external supplier part link" +msgstr "" + +#: company/models.py:246 +msgid "Supplier part description" +msgstr "" + +#: company/models.py:250 +msgid "Minimum charge (e.g. stocking fee)" +msgstr "" + +#: company/models.py:252 +msgid "Part packaging" +msgstr "" + +#: company/templates/company/notes.html:10 +#: company/templates/company/notes.html:27 +msgid "Company Notes" +msgstr "" + #: company/templates/company/partdelete.html:5 msgid "Are you sure you want to delete the following Supplier Parts?" msgstr "" +#: company/templates/company/tabs.html:9 +msgid "Supplier Parts" +msgstr "" + +#: company/templates/company/tabs.html:12 part/templates/part/tabs.html:17 +msgid "Stock" +msgstr "" + +#: company/templates/company/tabs.html:15 part/templates/part/tabs.html:43 +msgid "Purchase Orders" +msgstr "" + +#: company/templates/company/tabs.html:21 +msgid "Sales Orders" +msgstr "" + #: order/forms.py:21 msgid "Place order" msgstr "" @@ -309,150 +498,151 @@ msgstr "" msgid "Receive parts to this location" msgstr "" -#: order/models.py:63 +#: order/models.py:65 msgid "Order reference" msgstr "" -#: order/models.py:65 +#: order/models.py:67 msgid "Order description" msgstr "" -#: order/models.py:67 +#: order/models.py:69 msgid "Link to external page" msgstr "" -#: order/models.py:84 +#: order/models.py:86 msgid "Order notes" msgstr "" -#: order/models.py:126 +#: order/models.py:128 msgid "Company" msgstr "" -#: order/models.py:157 order/models.py:208 part/views.py:1032 -#: stock/models.py:438 +#: order/models.py:159 order/models.py:210 part/views.py:1065 +#: stock/models.py:440 msgid "Quantity must be greater than zero" msgstr "" -#: order/models.py:162 +#: order/models.py:164 msgid "Part supplier must match PO supplier" msgstr "" -#: order/models.py:203 +#: order/models.py:205 msgid "Lines can only be received against an order marked as 'Placed'" msgstr "" -#: order/models.py:252 +#: order/models.py:254 msgid "Item quantity" msgstr "" -#: order/models.py:254 +#: order/models.py:256 msgid "Line item reference" msgstr "" -#: order/models.py:256 +#: order/models.py:258 msgid "Line item notes" msgstr "" -#: order/models.py:282 stock/templates/stock/item.html:107 +#: order/models.py:284 stock/templates/stock/item_base.html:108 msgid "Purchase Order" msgstr "" -#: order/models.py:291 +#: order/models.py:293 msgid "Supplier part" msgstr "" -#: order/models.py:294 +#: order/models.py:296 msgid "Number of items received" msgstr "" -#: order/templates/order/purchase_order_detail.html:63 +#: order/templates/order/order_base.html:64 msgid "Purchase Order Details" msgstr "" -#: order/templates/order/purchase_order_detail.html:66 -#: stock/templates/stock/item.html:125 +#: order/templates/order/order_base.html:67 +#: stock/templates/stock/item_base.html:126 msgid "Supplier" msgstr "" -#: order/templates/order/purchase_order_detail.html:70 -#: stock/templates/stock/item.html:146 -msgid "Status" -msgstr "" - -#: order/templates/order/purchase_order_detail.html:74 -msgid "Created" -msgstr "" - -#: order/templates/order/purchase_order_detail.html:79 +#: order/templates/order/order_base.html:80 msgid "Issued" msgstr "" -#: order/templates/order/purchase_order_detail.html:85 -#: order/templates/order/purchase_order_detail.html:113 +#: order/templates/order/order_base.html:86 +#: order/templates/order/purchase_order_detail.html:31 msgid "Received" msgstr "" -#: order/templates/order/purchase_order_detail.html:106 +#: order/templates/order/order_notes.html:13 +#: order/templates/order/order_notes.html:29 +msgid "Order Notes" +msgstr "" + +#: order/templates/order/purchase_order_detail.html:15 +msgid "Add Line Item" +msgstr "" + +#: order/templates/order/purchase_order_detail.html:19 +msgid "Order Items" +msgstr "" + +#: order/templates/order/purchase_order_detail.html:24 msgid "Line" msgstr "" -#: order/templates/order/purchase_order_detail.html:109 +#: order/templates/order/purchase_order_detail.html:27 msgid "Order Code" msgstr "" -#: order/templates/order/purchase_order_detail.html:110 +#: order/templates/order/purchase_order_detail.html:28 msgid "Reference" msgstr "" -#: order/templates/order/purchase_order_detail.html:111 -#: stock/templates/stock/item.html:89 -#: stock/templates/stock/stock_adjust.html:18 -msgid "Quantity" -msgstr "" - -#: order/templates/order/purchase_order_detail.html:115 +#: order/templates/order/purchase_order_detail.html:33 msgid "Note" msgstr "" -#: order/templates/order/purchase_order_detail.html:168 -#: part/templates/part/detail.html:152 stock/templates/stock/item.html:151 -msgid "Notes" +#: order/templates/order/tabs.html:5 +msgid "Items" msgstr "" -#: order/views.py:141 +#: order/views.py:164 msgid "Confirm order cancellation" msgstr "" -#: order/views.py:174 +#: order/views.py:197 msgid "Confirm order placement" msgstr "" -#: order/views.py:328 +#: order/views.py:351 msgid "Items received" msgstr "" -#: order/views.py:342 +#: order/views.py:365 msgid "No destination set" msgstr "" -#: order/views.py:373 +#: order/views.py:396 msgid "Error converting quantity to number" msgstr "" -#: order/views.py:379 +#: order/views.py:402 msgid "Receive quantity less than zero" msgstr "" -#: order/views.py:740 +#: order/views.py:408 +msgid "No lines specified" +msgstr "" + +#: order/views.py:767 msgid "Invalid Purchase Order" msgstr "" -#: order/views.py:748 +#: order/views.py:775 msgid "Supplier must match for Part and Order" msgstr "" -#: order/views.py:753 +#: order/views.py:780 msgid "Invalid SupplierPart selection" msgstr "" @@ -489,187 +679,215 @@ msgstr "" msgid "Confirm part creation" msgstr "" -#: part/forms.py:173 +#: part/forms.py:172 msgid "Input quantity for price calculation" msgstr "" -#: part/forms.py:176 +#: part/forms.py:175 msgid "Select currency for price calculation" msgstr "" -#: part/models.py:55 +#: part/models.py:57 msgid "Default location for parts in this category" msgstr "" -#: part/models.py:58 +#: part/models.py:60 msgid "Default keywords for parts in this category" msgstr "" -#: part/models.py:307 +#: part/models.py:309 msgid "Part must be unique for name, IPN and revision" msgstr "" -#: part/models.py:321 +#: part/models.py:323 msgid "Part cannot be a template part if it is a variant of another part" msgstr "" -#: part/models.py:322 +#: part/models.py:324 msgid "Part cannot be a variant of another part if it is already a template" msgstr "" -#: part/models.py:326 part/templates/part/detail.html:17 +#: part/models.py:328 part/templates/part/detail.html:17 msgid "Part name" msgstr "" -#: part/models.py:330 +#: part/models.py:332 msgid "Is this part a template part?" msgstr "" -#: part/models.py:339 +#: part/models.py:341 msgid "Is this part a variant of another part?" msgstr "" -#: part/models.py:341 +#: part/models.py:343 msgid "Part description" msgstr "" -#: part/models.py:343 +#: part/models.py:345 msgid "Part keywords to improve visibility in search results" msgstr "" -#: part/models.py:348 +#: part/models.py:350 msgid "Part category" msgstr "" -#: part/models.py:350 +#: part/models.py:352 msgid "Internal Part Number" msgstr "" -#: part/models.py:352 +#: part/models.py:354 msgid "Part revision or version number" msgstr "" -#: part/models.py:354 +#: part/models.py:356 msgid "Link to extenal URL" msgstr "" -#: part/models.py:360 +#: part/models.py:362 msgid "Where is this item normally stored?" msgstr "" -#: part/models.py:404 +#: part/models.py:406 msgid "Default supplier part" msgstr "" -#: part/models.py:407 +#: part/models.py:409 msgid "Minimum allowed stock level" msgstr "" -#: part/models.py:409 +#: part/models.py:411 msgid "Stock keeping units for this part" msgstr "" -#: part/models.py:411 +#: part/models.py:413 msgid "Can this part be built from other parts?" msgstr "" -#: part/models.py:413 +#: part/models.py:415 msgid "Can this part be used to build other parts?" msgstr "" -#: part/models.py:415 +#: part/models.py:417 msgid "Does this part have tracking for unique items?" msgstr "" -#: part/models.py:417 +#: part/models.py:419 msgid "Can this part be purchased from external suppliers?" msgstr "" -#: part/models.py:419 +#: part/models.py:421 msgid "Can this part be sold to customers?" msgstr "" -#: part/models.py:421 +#: part/models.py:423 msgid "Is this part active?" msgstr "" -#: part/models.py:423 +#: part/models.py:425 msgid "Is this a virtual part, such as a software product or license?" msgstr "" #: part/models.py:427 +msgid "Part notes - supports Markdown formatting" +msgstr "" + +#: part/models.py:429 msgid "Stored BOM checksum" msgstr "" -#: part/models.py:934 +#: part/models.py:936 msgid "Select file to attach" msgstr "" -#: part/models.py:936 +#: part/models.py:938 msgid "File comment" msgstr "" -#: part/models.py:991 +#: part/models.py:993 msgid "Parameter template name must be unique" msgstr "" -#: part/models.py:996 +#: part/models.py:998 msgid "Parameter Name" msgstr "" -#: part/models.py:998 +#: part/models.py:1000 msgid "Parameter Units" msgstr "" -#: part/models.py:1024 +#: part/models.py:1026 msgid "Parent Part" msgstr "" -#: part/models.py:1026 +#: part/models.py:1028 msgid "Parameter Template" msgstr "" -#: part/models.py:1028 +#: part/models.py:1030 msgid "Parameter Value" msgstr "" -#: part/models.py:1052 +#: part/models.py:1054 msgid "Select parent part" msgstr "" -#: part/models.py:1060 +#: part/models.py:1062 msgid "Select part to be used in BOM" msgstr "" -#: part/models.py:1066 +#: part/models.py:1068 msgid "BOM quantity for this BOM item" msgstr "" -#: part/models.py:1069 +#: part/models.py:1071 msgid "Estimated build wastage quantity (absolute or percentage)" msgstr "" -#: part/models.py:1072 +#: part/models.py:1074 msgid "BOM item reference" msgstr "" -#: part/models.py:1075 +#: part/models.py:1077 msgid "BOM item notes" msgstr "" -#: part/models.py:1077 +#: part/models.py:1079 msgid "BOM line checksum" msgstr "" -#: part/models.py:1140 +#: part/models.py:1142 msgid "Part cannot be added to its own Bill of Materials" msgstr "" -#: part/models.py:1147 +#: part/models.py:1149 #, python-brace-format msgid "Part '{p1}' is used in BOM for '{p2}' (recursive)" msgstr "" +#: part/templates/part/attachments.html:8 +msgid "Part Attachments" +msgstr "" + +#: part/templates/part/attachments.html:14 +msgid "Add Attachment" +msgstr "" + +#: part/templates/part/attachments.html:22 +msgid "File" +msgstr "" + +#: part/templates/part/attachments.html:23 +msgid "Comment" +msgstr "" + +#: part/templates/part/attachments.html:34 +msgid "Edit attachment" +msgstr "" + +#: part/templates/part/attachments.html:37 +msgid "Delete attachment" +msgstr "" + #: part/templates/part/category.html:13 part/templates/part/category.html:69 msgid "Part Categories" msgstr "" @@ -726,11 +944,6 @@ msgstr "" msgid "Variant Of" msgstr "" -#: part/templates/part/detail.html:50 part/templates/part/part_base.html:91 -#: stock/templates/stock/item.html:119 -msgid "URL" -msgstr "" - #: part/templates/part/detail.html:55 msgid "Category" msgstr "" @@ -815,6 +1028,10 @@ msgstr "" msgid "Part cannot be sold to customers" msgstr "" +#: part/templates/part/notes.html:13 part/templates/part/notes.html:29 +msgid "Part Notes" +msgstr "" + #: part/templates/part/part_base.html:11 msgid "This part is not active" msgstr "" @@ -847,10 +1064,6 @@ msgstr "" msgid "Underway" msgstr "" -#: part/templates/part/tabs.html:6 -msgid "Details" -msgstr "" - #: part/templates/part/tabs.html:9 msgid "Parameters" msgstr "" @@ -859,15 +1072,11 @@ msgstr "" msgid "Variants" msgstr "" -#: part/templates/part/tabs.html:17 -msgid "Stock" -msgstr "" - #: part/templates/part/tabs.html:26 msgid "BOM" msgstr "" -#: part/templates/part/tabs.html:28 stock/templates/stock/item.html:101 +#: part/templates/part/tabs.html:28 stock/templates/stock/item_base.html:102 msgid "Build" msgstr "" @@ -879,11 +1088,7 @@ msgstr "" msgid "Suppliers" msgstr "" -#: part/templates/part/tabs.html:43 -msgid "Purchase Orders" -msgstr "" - -#: part/templates/part/tabs.html:48 +#: part/templates/part/tabs.html:48 stock/templates/stock/tabs.html:5 msgid "Tracking" msgstr "" @@ -896,27 +1101,27 @@ msgstr "" msgid "Set category for {n} parts" msgstr "" -#: part/views.py:773 +#: part/views.py:806 msgid "No BOM file provided" msgstr "" -#: part/views.py:1034 +#: part/views.py:1067 msgid "Enter a valid quantity" msgstr "" -#: part/views.py:1058 part/views.py:1061 +#: part/views.py:1091 part/views.py:1094 msgid "Select valid part" msgstr "" -#: part/views.py:1067 +#: part/views.py:1100 msgid "Duplicate part selected" msgstr "" -#: part/views.py:1095 +#: part/views.py:1128 msgid "Select a part" msgstr "" -#: part/views.py:1099 +#: part/views.py:1132 msgid "Specify quantity" msgstr "" @@ -944,179 +1149,176 @@ msgstr "" msgid "Set the destination as the default location for selected parts" msgstr "" -#: stock/models.py:202 +#: stock/models.py:204 #, python-brace-format msgid "" "A stock item with this serial number already exists for template part {part}" msgstr "" -#: stock/models.py:207 +#: stock/models.py:209 msgid "A stock item with this serial number already exists" msgstr "" -#: stock/models.py:226 +#: stock/models.py:228 #, python-brace-format msgid "Part type ('{pf}') must be {pe}" msgstr "" -#: stock/models.py:236 stock/models.py:245 +#: stock/models.py:238 stock/models.py:247 msgid "Quantity must be 1 for item with a serial number" msgstr "" -#: stock/models.py:237 +#: stock/models.py:239 msgid "Serial number cannot be set if quantity greater than 1" msgstr "" -#: stock/models.py:253 +#: stock/models.py:255 msgid "Stock item cannot be created for a template Part" msgstr "" -#: stock/models.py:262 +#: stock/models.py:264 msgid "Item cannot belong to itself" msgstr "" -#: stock/models.py:298 +#: stock/models.py:300 msgid "Base part" msgstr "" -#: stock/models.py:305 +#: stock/models.py:307 msgid "Select a matching supplier part for this stock item" msgstr "" -#: stock/models.py:309 +#: stock/models.py:311 msgid "Where is this stock item located?" msgstr "" -#: stock/models.py:313 +#: stock/models.py:315 msgid "Is this item installed in another item?" msgstr "" -#: stock/models.py:317 +#: stock/models.py:319 msgid "Item assigned to customer?" msgstr "" -#: stock/models.py:320 +#: stock/models.py:322 msgid "Serial number for this item" msgstr "" -#: stock/models.py:325 +#: stock/models.py:327 msgid "Batch code for this stock item" msgstr "" -#: stock/models.py:334 +#: stock/models.py:336 msgid "Build for this stock item" msgstr "" -#: stock/models.py:343 +#: stock/models.py:345 msgid "Purchase order for this stock item" msgstr "" -#: stock/models.py:354 +#: stock/models.py:356 msgid "Delete this Stock Item when stock is depleted" msgstr "" -#: stock/models.py:361 +#: stock/models.py:363 stock/templates/stock/item_notes.html:13 +#: stock/templates/stock/item_notes.html:29 msgid "Stock Item Notes" msgstr "" -#: stock/models.py:435 +#: stock/models.py:437 msgid "Quantity must be integer" msgstr "" -#: stock/models.py:441 +#: stock/models.py:443 #, python-brace-format msgid "Quantity must not exceed available stock quantity ({n})" msgstr "" -#: stock/models.py:444 stock/models.py:447 +#: stock/models.py:446 stock/models.py:449 msgid "Serial numbers must be a list of integers" msgstr "" -#: stock/models.py:450 +#: stock/models.py:452 msgid "Quantity does not match serial numbers" msgstr "" -#: stock/models.py:460 +#: stock/models.py:462 msgid "Serial numbers already exist: " msgstr "" -#: stock/models.py:481 +#: stock/models.py:483 msgid "Add serial number" msgstr "" -#: stock/models.py:484 +#: stock/models.py:486 #, python-brace-format msgid "Serialized {n} items" msgstr "" -#: stock/models.py:750 +#: stock/models.py:752 msgid "Tracking entry title" msgstr "" -#: stock/models.py:752 +#: stock/models.py:754 msgid "Entry notes" msgstr "" -#: stock/models.py:754 +#: stock/models.py:756 msgid "Link to external page for further information" msgstr "" -#: stock/templates/stock/item.html:9 +#: stock/templates/stock/item.html:12 +msgid "Stock Tracking Information" +msgstr "" + +#: stock/templates/stock/item_base.html:10 msgid "Stock Item Details" msgstr "" -#: stock/templates/stock/item.html:52 +#: stock/templates/stock/item_base.html:53 msgid "" "This stock item is serialized - it has a unique serial number and the " "quantity cannot be adjusted." msgstr "" -#: stock/templates/stock/item.html:56 +#: stock/templates/stock/item_base.html:57 msgid "" "This stock item will be automatically deleted when all stock is depleted." msgstr "" -#: stock/templates/stock/item.html:73 +#: stock/templates/stock/item_base.html:74 msgid "Belongs To" msgstr "" -#: stock/templates/stock/item.html:78 +#: stock/templates/stock/item_base.html:79 #: stock/templates/stock/stock_adjust.html:17 msgid "Location" msgstr "" -#: stock/templates/stock/item.html:84 +#: stock/templates/stock/item_base.html:85 msgid "Serial Number" msgstr "" -#: stock/templates/stock/item.html:95 -msgid "Batch" -msgstr "" - -#: stock/templates/stock/item.html:113 +#: stock/templates/stock/item_base.html:114 msgid "Customer" msgstr "" -#: stock/templates/stock/item.html:129 +#: stock/templates/stock/item_base.html:130 msgid "Supplier Part" msgstr "" -#: stock/templates/stock/item.html:134 +#: stock/templates/stock/item_base.html:135 msgid "Last Updated" msgstr "" -#: stock/templates/stock/item.html:138 +#: stock/templates/stock/item_base.html:139 msgid "Last Stocktake" msgstr "" -#: stock/templates/stock/item.html:142 +#: stock/templates/stock/item_base.html:143 msgid "No stocktake performed" msgstr "" -#: stock/templates/stock/item.html:160 -msgid "Stock Tracking Information" -msgstr "" - #: stock/templates/stock/location.html:37 msgid "Location Details" msgstr "" @@ -1150,140 +1352,164 @@ msgstr "" msgid "Stock Item" msgstr "" -#: stock/views.py:96 +#: stock/views.py:117 msgid "Edit Stock Location" msgstr "" -#: stock/views.py:120 +#: stock/views.py:141 msgid "Stock Location QR code" msgstr "" -#: stock/views.py:135 +#: stock/views.py:156 msgid "Stock Export Options" msgstr "" -#: stock/views.py:243 +#: stock/views.py:264 msgid "Stock Item QR Code" msgstr "" -#: stock/views.py:266 +#: stock/views.py:287 msgid "Adjust Stock" msgstr "" -#: stock/views.py:375 +#: stock/views.py:396 msgid "Move Stock Items" msgstr "" -#: stock/views.py:376 +#: stock/views.py:397 msgid "Count Stock Items" msgstr "" -#: stock/views.py:377 +#: stock/views.py:398 msgid "Remove From Stock" msgstr "" -#: stock/views.py:378 +#: stock/views.py:399 msgid "Add Stock Items" msgstr "" -#: stock/views.py:379 +#: stock/views.py:400 msgid "Delete Stock Items" msgstr "" -#: stock/views.py:407 +#: stock/views.py:428 msgid "Must enter integer value" msgstr "" -#: stock/views.py:412 +#: stock/views.py:433 msgid "Quantity must be positive" msgstr "" -#: stock/views.py:419 +#: stock/views.py:440 #, python-brace-format msgid "Quantity must not exceed {x}" msgstr "" -#: stock/views.py:427 +#: stock/views.py:448 msgid "Confirm stock adjustment" msgstr "" -#: stock/views.py:498 +#: stock/views.py:519 #, python-brace-format msgid "Added stock to {n} items" msgstr "" -#: stock/views.py:513 +#: stock/views.py:534 #, python-brace-format msgid "Removed stock from {n} items" msgstr "" -#: stock/views.py:526 +#: stock/views.py:547 #, python-brace-format msgid "Counted stock for {n} items" msgstr "" -#: stock/views.py:554 +#: stock/views.py:575 msgid "No items were moved" msgstr "" -#: stock/views.py:557 +#: stock/views.py:578 #, python-brace-format msgid "Moved {n} items to {dest}" msgstr "" -#: stock/views.py:576 +#: stock/views.py:597 #, python-brace-format msgid "Deleted {n} stock items" msgstr "" -#: stock/views.py:588 +#: stock/views.py:609 msgid "Edit Stock Item" msgstr "" -#: stock/views.py:624 +#: stock/views.py:645 msgid "Create new Stock Location" msgstr "" -#: stock/views.py:645 +#: stock/views.py:666 msgid "Serialize Stock" msgstr "" -#: stock/views.py:725 +#: stock/views.py:746 msgid "Create new Stock Item" msgstr "" -#: stock/views.py:789 +#: stock/views.py:810 msgid "Copy Stock Item" msgstr "" -#: stock/views.py:839 +#: stock/views.py:860 msgid "Invalid quantity" msgstr "" -#: stock/views.py:842 +#: stock/views.py:863 msgid "Invalid part selection" msgstr "" -#: stock/views.py:904 +#: stock/views.py:925 msgid "Created new stock item" msgstr "" -#: stock/views.py:921 +#: stock/views.py:942 msgid "Delete Stock Location" msgstr "" -#: stock/views.py:934 +#: stock/views.py:955 msgid "Delete Stock Item" msgstr "" -#: stock/views.py:945 +#: stock/views.py:966 msgid "Delete Stock Tracking Entry" msgstr "" -#: stock/views.py:962 +#: stock/views.py:983 msgid "Edit Stock Tracking Entry" msgstr "" -#: stock/views.py:971 +#: stock/views.py:992 msgid "Add Stock Tracking Entry" msgstr "" + +#: templates/about.html:18 +msgid "InvenTree Version Information" +msgstr "" + +#: templates/about.html:21 +msgid "Version" +msgstr "" + +#: templates/about.html:24 +msgid "Commit Hash" +msgstr "" + +#: templates/about.html:27 +msgid "Commit Date" +msgstr "" + +#: templates/about.html:33 +msgid "InvenTree Documentation" +msgstr "" + +#: templates/about.html:37 +msgid "View Code on GitHub" +msgstr "" diff --git a/InvenTree/locale/es/LC_MESSAGES/django.po b/InvenTree/locale/es/LC_MESSAGES/django.po index 5266643986..634d43140c 100644 --- a/InvenTree/locale/es/LC_MESSAGES/django.po +++ b/InvenTree/locale/es/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-01-05 22:23+0000\n" +"POT-Creation-Date: 2020-02-02 01:39+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -18,7 +18,7 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -#: InvenTree/helpers.py:186 order/models.py:159 order/models.py:210 +#: InvenTree/helpers.py:186 order/models.py:161 order/models.py:212 msgid "Invalid quantity provided" msgstr "" @@ -46,19 +46,19 @@ msgstr "" msgid "Number of unique serial number ({s}) must match quantity ({q})" msgstr "" -#: InvenTree/settings.py:235 +#: InvenTree/settings.py:270 msgid "English" msgstr "" -#: InvenTree/settings.py:236 +#: InvenTree/settings.py:271 msgid "German" msgstr "" -#: InvenTree/settings.py:237 +#: InvenTree/settings.py:272 msgid "French" msgstr "" -#: InvenTree/settings.py:238 +#: InvenTree/settings.py:273 msgid "Polish" msgstr "" @@ -129,71 +129,71 @@ msgstr "" msgid "Overage must be an integer value or a percentage" msgstr "" -#: build/forms.py:36 +#: build/forms.py:35 msgid "Confirm" msgstr "" -#: build/forms.py:53 stock/forms.py:34 +#: build/forms.py:52 stock/forms.py:34 msgid "Enter unique serial numbers (or leave blank)" msgstr "" -#: build/forms.py:55 +#: build/forms.py:54 msgid "Confirm build completion" msgstr "" -#: build/models.py:51 +#: build/models.py:53 msgid "Brief description of the build" msgstr "" -#: build/models.py:60 +#: build/models.py:62 msgid "Select part to build" msgstr "" -#: build/models.py:66 +#: build/models.py:68 msgid "" "Select location to take stock from for this build (leave blank to take from " "any stock location)" msgstr "" -#: build/models.py:72 +#: build/models.py:74 msgid "Number of parts to build" msgstr "" -#: build/models.py:78 +#: build/models.py:80 msgid "Build status" msgstr "" -#: build/models.py:81 +#: build/models.py:83 msgid "Batch code for this build output" msgstr "" -#: build/models.py:93 +#: build/models.py:95 msgid "Link to external URL" msgstr "" -#: build/models.py:95 +#: build/models.py:97 msgid "Extra build notes" msgstr "" -#: build/models.py:380 +#: build/models.py:382 #, python-brace-format msgid "Selected stock item not found in BOM for part '{p}'" msgstr "" -#: build/models.py:383 +#: build/models.py:385 #, python-brace-format msgid "Allocated quantity ({n}) must not exceed available quantity ({q})" msgstr "" -#: build/models.py:401 +#: build/models.py:403 msgid "Build to allocate parts" msgstr "" -#: build/models.py:408 +#: build/models.py:410 msgid "Stock Item to allocate to build" msgstr "" -#: build/models.py:416 +#: build/models.py:418 msgid "Stock quantity to allocate to build" msgstr "" @@ -211,7 +211,8 @@ msgstr "" #: build/templates/build/allocate_edit.html:19 #: build/templates/build/allocate_view.html:17 -#: order/templates/order/purchase_order_detail.html:107 +#: build/templates/build/detail.html:17 +#: order/templates/order/purchase_order_detail.html:25 msgid "Part" msgstr "" @@ -238,7 +239,7 @@ msgid "Order Parts" msgstr "" #: build/templates/build/allocate_view.html:18 -#: order/templates/order/purchase_order_detail.html:108 +#: order/templates/order/purchase_order_detail.html:26 #: part/templates/part/detail.html:33 msgid "Description" msgstr "" @@ -248,7 +249,98 @@ msgstr "" msgid "On Order" msgstr "" -#: build/views.py:289 stock/views.py:863 +#: build/templates/build/detail.html:8 +msgid "Build Details" +msgstr "" + +#: build/templates/build/detail.html:14 +msgid "Title" +msgstr "" + +#: build/templates/build/detail.html:20 +#: order/templates/order/purchase_order_detail.html:29 +#: stock/templates/stock/item_base.html:90 +#: stock/templates/stock/stock_adjust.html:18 +msgid "Quantity" +msgstr "" + +#: build/templates/build/detail.html:23 +msgid "Stock Source" +msgstr "" + +#: build/templates/build/detail.html:28 +msgid "Stock can be taken from any available location." +msgstr "" + +#: build/templates/build/detail.html:33 +#: order/templates/order/order_base.html:71 +#: stock/templates/stock/item_base.html:147 +msgid "Status" +msgstr "" + +#: build/templates/build/detail.html:37 stock/templates/stock/item_base.html:96 +msgid "Batch" +msgstr "" + +#: build/templates/build/detail.html:42 part/templates/part/detail.html:50 +#: part/templates/part/part_base.html:91 +#: stock/templates/stock/item_base.html:120 +msgid "URL" +msgstr "" + +#: build/templates/build/detail.html:46 +#: order/templates/order/order_base.html:75 +msgid "Created" +msgstr "" + +#: build/templates/build/detail.html:50 +msgid "Enough Parts?" +msgstr "" + +#: build/templates/build/detail.html:53 +msgid "Yes" +msgstr "" + +#: build/templates/build/detail.html:55 +msgid "No" +msgstr "" + +#: build/templates/build/detail.html:62 +msgid "Completed" +msgstr "" + +#: build/templates/build/notes.html:13 build/templates/build/notes.html:30 +msgid "Build Notes" +msgstr "" + +#: build/templates/build/notes.html:20 company/templates/company/notes.html:17 +#: order/templates/order/order_notes.html:21 part/templates/part/notes.html:20 +#: stock/templates/stock/item_notes.html:21 +msgid "Save" +msgstr "" + +#: build/templates/build/notes.html:33 company/templates/company/notes.html:30 +#: order/templates/order/order_notes.html:32 part/templates/part/notes.html:32 +#: stock/templates/stock/item_notes.html:32 +msgid "Edit notes" +msgstr "" + +#: build/templates/build/tabs.html:5 company/templates/company/tabs.html:5 +#: part/templates/part/tabs.html:6 +msgid "Details" +msgstr "" + +#: build/templates/build/tabs.html:8 company/models.py:248 +#: company/templates/company/tabs.html:26 order/templates/order/tabs.html:8 +#: part/templates/part/tabs.html:58 stock/templates/stock/tabs.html:8 +msgid "Notes" +msgstr "" + +#: build/templates/build/tabs.html:11 +msgid "Assign Parts" +msgstr "" + +#: build/views.py:290 stock/views.py:884 #, python-brace-format msgid "The following serial numbers already exist: ({sn})" msgstr "" @@ -289,10 +381,107 @@ msgstr "" msgid "Use this currency as the base currency" msgstr "" +#: company/models.py:74 +msgid "Company name" +msgstr "" + +#: company/models.py:76 +msgid "Description of the company" +msgstr "" + +#: company/models.py:78 +msgid "Company website URL" +msgstr "" + +#: company/models.py:81 +msgid "Company address" +msgstr "" + +#: company/models.py:84 +msgid "Contact phone number" +msgstr "" + +#: company/models.py:86 +msgid "Contact email address" +msgstr "" + +#: company/models.py:89 +msgid "Point of contact" +msgstr "" + +#: company/models.py:91 +msgid "Link to external company information" +msgstr "" + +#: company/models.py:97 +msgid "Do you sell items to this company?" +msgstr "" + +#: company/models.py:99 +msgid "Do you purchase items from this company?" +msgstr "" + +#: company/models.py:229 +msgid "Select part" +msgstr "" + +#: company/models.py:235 +msgid "Select supplier" +msgstr "" + +#: company/models.py:238 +msgid "Supplier stock keeping unit" +msgstr "" + +#: company/models.py:240 +msgid "Manufacturer" +msgstr "" + +#: company/models.py:242 +msgid "Manufacturer part number" +msgstr "" + +#: company/models.py:244 +msgid "URL for external supplier part link" +msgstr "" + +#: company/models.py:246 +msgid "Supplier part description" +msgstr "" + +#: company/models.py:250 +msgid "Minimum charge (e.g. stocking fee)" +msgstr "" + +#: company/models.py:252 +msgid "Part packaging" +msgstr "" + +#: company/templates/company/notes.html:10 +#: company/templates/company/notes.html:27 +msgid "Company Notes" +msgstr "" + #: company/templates/company/partdelete.html:5 msgid "Are you sure you want to delete the following Supplier Parts?" msgstr "" +#: company/templates/company/tabs.html:9 +msgid "Supplier Parts" +msgstr "" + +#: company/templates/company/tabs.html:12 part/templates/part/tabs.html:17 +msgid "Stock" +msgstr "" + +#: company/templates/company/tabs.html:15 part/templates/part/tabs.html:43 +msgid "Purchase Orders" +msgstr "" + +#: company/templates/company/tabs.html:21 +msgid "Sales Orders" +msgstr "" + #: order/forms.py:21 msgid "Place order" msgstr "" @@ -309,150 +498,151 @@ msgstr "" msgid "Receive parts to this location" msgstr "" -#: order/models.py:63 +#: order/models.py:65 msgid "Order reference" msgstr "" -#: order/models.py:65 +#: order/models.py:67 msgid "Order description" msgstr "" -#: order/models.py:67 +#: order/models.py:69 msgid "Link to external page" msgstr "" -#: order/models.py:84 +#: order/models.py:86 msgid "Order notes" msgstr "" -#: order/models.py:126 +#: order/models.py:128 msgid "Company" msgstr "" -#: order/models.py:157 order/models.py:208 part/views.py:1032 -#: stock/models.py:438 +#: order/models.py:159 order/models.py:210 part/views.py:1065 +#: stock/models.py:440 msgid "Quantity must be greater than zero" msgstr "" -#: order/models.py:162 +#: order/models.py:164 msgid "Part supplier must match PO supplier" msgstr "" -#: order/models.py:203 +#: order/models.py:205 msgid "Lines can only be received against an order marked as 'Placed'" msgstr "" -#: order/models.py:252 +#: order/models.py:254 msgid "Item quantity" msgstr "" -#: order/models.py:254 +#: order/models.py:256 msgid "Line item reference" msgstr "" -#: order/models.py:256 +#: order/models.py:258 msgid "Line item notes" msgstr "" -#: order/models.py:282 stock/templates/stock/item.html:107 +#: order/models.py:284 stock/templates/stock/item_base.html:108 msgid "Purchase Order" msgstr "" -#: order/models.py:291 +#: order/models.py:293 msgid "Supplier part" msgstr "" -#: order/models.py:294 +#: order/models.py:296 msgid "Number of items received" msgstr "" -#: order/templates/order/purchase_order_detail.html:63 +#: order/templates/order/order_base.html:64 msgid "Purchase Order Details" msgstr "" -#: order/templates/order/purchase_order_detail.html:66 -#: stock/templates/stock/item.html:125 +#: order/templates/order/order_base.html:67 +#: stock/templates/stock/item_base.html:126 msgid "Supplier" msgstr "" -#: order/templates/order/purchase_order_detail.html:70 -#: stock/templates/stock/item.html:146 -msgid "Status" -msgstr "" - -#: order/templates/order/purchase_order_detail.html:74 -msgid "Created" -msgstr "" - -#: order/templates/order/purchase_order_detail.html:79 +#: order/templates/order/order_base.html:80 msgid "Issued" msgstr "" -#: order/templates/order/purchase_order_detail.html:85 -#: order/templates/order/purchase_order_detail.html:113 +#: order/templates/order/order_base.html:86 +#: order/templates/order/purchase_order_detail.html:31 msgid "Received" msgstr "" -#: order/templates/order/purchase_order_detail.html:106 +#: order/templates/order/order_notes.html:13 +#: order/templates/order/order_notes.html:29 +msgid "Order Notes" +msgstr "" + +#: order/templates/order/purchase_order_detail.html:15 +msgid "Add Line Item" +msgstr "" + +#: order/templates/order/purchase_order_detail.html:19 +msgid "Order Items" +msgstr "" + +#: order/templates/order/purchase_order_detail.html:24 msgid "Line" msgstr "" -#: order/templates/order/purchase_order_detail.html:109 +#: order/templates/order/purchase_order_detail.html:27 msgid "Order Code" msgstr "" -#: order/templates/order/purchase_order_detail.html:110 +#: order/templates/order/purchase_order_detail.html:28 msgid "Reference" msgstr "" -#: order/templates/order/purchase_order_detail.html:111 -#: stock/templates/stock/item.html:89 -#: stock/templates/stock/stock_adjust.html:18 -msgid "Quantity" -msgstr "" - -#: order/templates/order/purchase_order_detail.html:115 +#: order/templates/order/purchase_order_detail.html:33 msgid "Note" msgstr "" -#: order/templates/order/purchase_order_detail.html:168 -#: part/templates/part/detail.html:152 stock/templates/stock/item.html:151 -msgid "Notes" +#: order/templates/order/tabs.html:5 +msgid "Items" msgstr "" -#: order/views.py:141 +#: order/views.py:164 msgid "Confirm order cancellation" msgstr "" -#: order/views.py:174 +#: order/views.py:197 msgid "Confirm order placement" msgstr "" -#: order/views.py:328 +#: order/views.py:351 msgid "Items received" msgstr "" -#: order/views.py:342 +#: order/views.py:365 msgid "No destination set" msgstr "" -#: order/views.py:373 +#: order/views.py:396 msgid "Error converting quantity to number" msgstr "" -#: order/views.py:379 +#: order/views.py:402 msgid "Receive quantity less than zero" msgstr "" -#: order/views.py:740 +#: order/views.py:408 +msgid "No lines specified" +msgstr "" + +#: order/views.py:767 msgid "Invalid Purchase Order" msgstr "" -#: order/views.py:748 +#: order/views.py:775 msgid "Supplier must match for Part and Order" msgstr "" -#: order/views.py:753 +#: order/views.py:780 msgid "Invalid SupplierPart selection" msgstr "" @@ -489,187 +679,215 @@ msgstr "" msgid "Confirm part creation" msgstr "" -#: part/forms.py:173 +#: part/forms.py:172 msgid "Input quantity for price calculation" msgstr "" -#: part/forms.py:176 +#: part/forms.py:175 msgid "Select currency for price calculation" msgstr "" -#: part/models.py:55 +#: part/models.py:57 msgid "Default location for parts in this category" msgstr "" -#: part/models.py:58 +#: part/models.py:60 msgid "Default keywords for parts in this category" msgstr "" -#: part/models.py:307 +#: part/models.py:309 msgid "Part must be unique for name, IPN and revision" msgstr "" -#: part/models.py:321 +#: part/models.py:323 msgid "Part cannot be a template part if it is a variant of another part" msgstr "" -#: part/models.py:322 +#: part/models.py:324 msgid "Part cannot be a variant of another part if it is already a template" msgstr "" -#: part/models.py:326 part/templates/part/detail.html:17 +#: part/models.py:328 part/templates/part/detail.html:17 msgid "Part name" msgstr "" -#: part/models.py:330 +#: part/models.py:332 msgid "Is this part a template part?" msgstr "" -#: part/models.py:339 +#: part/models.py:341 msgid "Is this part a variant of another part?" msgstr "" -#: part/models.py:341 +#: part/models.py:343 msgid "Part description" msgstr "" -#: part/models.py:343 +#: part/models.py:345 msgid "Part keywords to improve visibility in search results" msgstr "" -#: part/models.py:348 +#: part/models.py:350 msgid "Part category" msgstr "" -#: part/models.py:350 +#: part/models.py:352 msgid "Internal Part Number" msgstr "" -#: part/models.py:352 +#: part/models.py:354 msgid "Part revision or version number" msgstr "" -#: part/models.py:354 +#: part/models.py:356 msgid "Link to extenal URL" msgstr "" -#: part/models.py:360 +#: part/models.py:362 msgid "Where is this item normally stored?" msgstr "" -#: part/models.py:404 +#: part/models.py:406 msgid "Default supplier part" msgstr "" -#: part/models.py:407 +#: part/models.py:409 msgid "Minimum allowed stock level" msgstr "" -#: part/models.py:409 +#: part/models.py:411 msgid "Stock keeping units for this part" msgstr "" -#: part/models.py:411 +#: part/models.py:413 msgid "Can this part be built from other parts?" msgstr "" -#: part/models.py:413 +#: part/models.py:415 msgid "Can this part be used to build other parts?" msgstr "" -#: part/models.py:415 +#: part/models.py:417 msgid "Does this part have tracking for unique items?" msgstr "" -#: part/models.py:417 +#: part/models.py:419 msgid "Can this part be purchased from external suppliers?" msgstr "" -#: part/models.py:419 +#: part/models.py:421 msgid "Can this part be sold to customers?" msgstr "" -#: part/models.py:421 +#: part/models.py:423 msgid "Is this part active?" msgstr "" -#: part/models.py:423 +#: part/models.py:425 msgid "Is this a virtual part, such as a software product or license?" msgstr "" #: part/models.py:427 +msgid "Part notes - supports Markdown formatting" +msgstr "" + +#: part/models.py:429 msgid "Stored BOM checksum" msgstr "" -#: part/models.py:934 +#: part/models.py:936 msgid "Select file to attach" msgstr "" -#: part/models.py:936 +#: part/models.py:938 msgid "File comment" msgstr "" -#: part/models.py:991 +#: part/models.py:993 msgid "Parameter template name must be unique" msgstr "" -#: part/models.py:996 +#: part/models.py:998 msgid "Parameter Name" msgstr "" -#: part/models.py:998 +#: part/models.py:1000 msgid "Parameter Units" msgstr "" -#: part/models.py:1024 +#: part/models.py:1026 msgid "Parent Part" msgstr "" -#: part/models.py:1026 +#: part/models.py:1028 msgid "Parameter Template" msgstr "" -#: part/models.py:1028 +#: part/models.py:1030 msgid "Parameter Value" msgstr "" -#: part/models.py:1052 +#: part/models.py:1054 msgid "Select parent part" msgstr "" -#: part/models.py:1060 +#: part/models.py:1062 msgid "Select part to be used in BOM" msgstr "" -#: part/models.py:1066 +#: part/models.py:1068 msgid "BOM quantity for this BOM item" msgstr "" -#: part/models.py:1069 +#: part/models.py:1071 msgid "Estimated build wastage quantity (absolute or percentage)" msgstr "" -#: part/models.py:1072 +#: part/models.py:1074 msgid "BOM item reference" msgstr "" -#: part/models.py:1075 +#: part/models.py:1077 msgid "BOM item notes" msgstr "" -#: part/models.py:1077 +#: part/models.py:1079 msgid "BOM line checksum" msgstr "" -#: part/models.py:1140 +#: part/models.py:1142 msgid "Part cannot be added to its own Bill of Materials" msgstr "" -#: part/models.py:1147 +#: part/models.py:1149 #, python-brace-format msgid "Part '{p1}' is used in BOM for '{p2}' (recursive)" msgstr "" +#: part/templates/part/attachments.html:8 +msgid "Part Attachments" +msgstr "" + +#: part/templates/part/attachments.html:14 +msgid "Add Attachment" +msgstr "" + +#: part/templates/part/attachments.html:22 +msgid "File" +msgstr "" + +#: part/templates/part/attachments.html:23 +msgid "Comment" +msgstr "" + +#: part/templates/part/attachments.html:34 +msgid "Edit attachment" +msgstr "" + +#: part/templates/part/attachments.html:37 +msgid "Delete attachment" +msgstr "" + #: part/templates/part/category.html:13 part/templates/part/category.html:69 msgid "Part Categories" msgstr "" @@ -726,11 +944,6 @@ msgstr "" msgid "Variant Of" msgstr "" -#: part/templates/part/detail.html:50 part/templates/part/part_base.html:91 -#: stock/templates/stock/item.html:119 -msgid "URL" -msgstr "" - #: part/templates/part/detail.html:55 msgid "Category" msgstr "" @@ -815,6 +1028,10 @@ msgstr "" msgid "Part cannot be sold to customers" msgstr "" +#: part/templates/part/notes.html:13 part/templates/part/notes.html:29 +msgid "Part Notes" +msgstr "" + #: part/templates/part/part_base.html:11 msgid "This part is not active" msgstr "" @@ -847,10 +1064,6 @@ msgstr "" msgid "Underway" msgstr "" -#: part/templates/part/tabs.html:6 -msgid "Details" -msgstr "" - #: part/templates/part/tabs.html:9 msgid "Parameters" msgstr "" @@ -859,15 +1072,11 @@ msgstr "" msgid "Variants" msgstr "" -#: part/templates/part/tabs.html:17 -msgid "Stock" -msgstr "" - #: part/templates/part/tabs.html:26 msgid "BOM" msgstr "" -#: part/templates/part/tabs.html:28 stock/templates/stock/item.html:101 +#: part/templates/part/tabs.html:28 stock/templates/stock/item_base.html:102 msgid "Build" msgstr "" @@ -879,11 +1088,7 @@ msgstr "" msgid "Suppliers" msgstr "" -#: part/templates/part/tabs.html:43 -msgid "Purchase Orders" -msgstr "" - -#: part/templates/part/tabs.html:48 +#: part/templates/part/tabs.html:48 stock/templates/stock/tabs.html:5 msgid "Tracking" msgstr "" @@ -896,27 +1101,27 @@ msgstr "" msgid "Set category for {n} parts" msgstr "" -#: part/views.py:773 +#: part/views.py:806 msgid "No BOM file provided" msgstr "" -#: part/views.py:1034 +#: part/views.py:1067 msgid "Enter a valid quantity" msgstr "" -#: part/views.py:1058 part/views.py:1061 +#: part/views.py:1091 part/views.py:1094 msgid "Select valid part" msgstr "" -#: part/views.py:1067 +#: part/views.py:1100 msgid "Duplicate part selected" msgstr "" -#: part/views.py:1095 +#: part/views.py:1128 msgid "Select a part" msgstr "" -#: part/views.py:1099 +#: part/views.py:1132 msgid "Specify quantity" msgstr "" @@ -944,179 +1149,176 @@ msgstr "" msgid "Set the destination as the default location for selected parts" msgstr "" -#: stock/models.py:202 +#: stock/models.py:204 #, python-brace-format msgid "" "A stock item with this serial number already exists for template part {part}" msgstr "" -#: stock/models.py:207 +#: stock/models.py:209 msgid "A stock item with this serial number already exists" msgstr "" -#: stock/models.py:226 +#: stock/models.py:228 #, python-brace-format msgid "Part type ('{pf}') must be {pe}" msgstr "" -#: stock/models.py:236 stock/models.py:245 +#: stock/models.py:238 stock/models.py:247 msgid "Quantity must be 1 for item with a serial number" msgstr "" -#: stock/models.py:237 +#: stock/models.py:239 msgid "Serial number cannot be set if quantity greater than 1" msgstr "" -#: stock/models.py:253 +#: stock/models.py:255 msgid "Stock item cannot be created for a template Part" msgstr "" -#: stock/models.py:262 +#: stock/models.py:264 msgid "Item cannot belong to itself" msgstr "" -#: stock/models.py:298 +#: stock/models.py:300 msgid "Base part" msgstr "" -#: stock/models.py:305 +#: stock/models.py:307 msgid "Select a matching supplier part for this stock item" msgstr "" -#: stock/models.py:309 +#: stock/models.py:311 msgid "Where is this stock item located?" msgstr "" -#: stock/models.py:313 +#: stock/models.py:315 msgid "Is this item installed in another item?" msgstr "" -#: stock/models.py:317 +#: stock/models.py:319 msgid "Item assigned to customer?" msgstr "" -#: stock/models.py:320 +#: stock/models.py:322 msgid "Serial number for this item" msgstr "" -#: stock/models.py:325 +#: stock/models.py:327 msgid "Batch code for this stock item" msgstr "" -#: stock/models.py:334 +#: stock/models.py:336 msgid "Build for this stock item" msgstr "" -#: stock/models.py:343 +#: stock/models.py:345 msgid "Purchase order for this stock item" msgstr "" -#: stock/models.py:354 +#: stock/models.py:356 msgid "Delete this Stock Item when stock is depleted" msgstr "" -#: stock/models.py:361 +#: stock/models.py:363 stock/templates/stock/item_notes.html:13 +#: stock/templates/stock/item_notes.html:29 msgid "Stock Item Notes" msgstr "" -#: stock/models.py:435 +#: stock/models.py:437 msgid "Quantity must be integer" msgstr "" -#: stock/models.py:441 +#: stock/models.py:443 #, python-brace-format msgid "Quantity must not exceed available stock quantity ({n})" msgstr "" -#: stock/models.py:444 stock/models.py:447 +#: stock/models.py:446 stock/models.py:449 msgid "Serial numbers must be a list of integers" msgstr "" -#: stock/models.py:450 +#: stock/models.py:452 msgid "Quantity does not match serial numbers" msgstr "" -#: stock/models.py:460 +#: stock/models.py:462 msgid "Serial numbers already exist: " msgstr "" -#: stock/models.py:481 +#: stock/models.py:483 msgid "Add serial number" msgstr "" -#: stock/models.py:484 +#: stock/models.py:486 #, python-brace-format msgid "Serialized {n} items" msgstr "" -#: stock/models.py:750 +#: stock/models.py:752 msgid "Tracking entry title" msgstr "" -#: stock/models.py:752 +#: stock/models.py:754 msgid "Entry notes" msgstr "" -#: stock/models.py:754 +#: stock/models.py:756 msgid "Link to external page for further information" msgstr "" -#: stock/templates/stock/item.html:9 +#: stock/templates/stock/item.html:12 +msgid "Stock Tracking Information" +msgstr "" + +#: stock/templates/stock/item_base.html:10 msgid "Stock Item Details" msgstr "" -#: stock/templates/stock/item.html:52 +#: stock/templates/stock/item_base.html:53 msgid "" "This stock item is serialized - it has a unique serial number and the " "quantity cannot be adjusted." msgstr "" -#: stock/templates/stock/item.html:56 +#: stock/templates/stock/item_base.html:57 msgid "" "This stock item will be automatically deleted when all stock is depleted." msgstr "" -#: stock/templates/stock/item.html:73 +#: stock/templates/stock/item_base.html:74 msgid "Belongs To" msgstr "" -#: stock/templates/stock/item.html:78 +#: stock/templates/stock/item_base.html:79 #: stock/templates/stock/stock_adjust.html:17 msgid "Location" msgstr "" -#: stock/templates/stock/item.html:84 +#: stock/templates/stock/item_base.html:85 msgid "Serial Number" msgstr "" -#: stock/templates/stock/item.html:95 -msgid "Batch" -msgstr "" - -#: stock/templates/stock/item.html:113 +#: stock/templates/stock/item_base.html:114 msgid "Customer" msgstr "" -#: stock/templates/stock/item.html:129 +#: stock/templates/stock/item_base.html:130 msgid "Supplier Part" msgstr "" -#: stock/templates/stock/item.html:134 +#: stock/templates/stock/item_base.html:135 msgid "Last Updated" msgstr "" -#: stock/templates/stock/item.html:138 +#: stock/templates/stock/item_base.html:139 msgid "Last Stocktake" msgstr "" -#: stock/templates/stock/item.html:142 +#: stock/templates/stock/item_base.html:143 msgid "No stocktake performed" msgstr "" -#: stock/templates/stock/item.html:160 -msgid "Stock Tracking Information" -msgstr "" - #: stock/templates/stock/location.html:37 msgid "Location Details" msgstr "" @@ -1150,140 +1352,164 @@ msgstr "" msgid "Stock Item" msgstr "" -#: stock/views.py:96 +#: stock/views.py:117 msgid "Edit Stock Location" msgstr "" -#: stock/views.py:120 +#: stock/views.py:141 msgid "Stock Location QR code" msgstr "" -#: stock/views.py:135 +#: stock/views.py:156 msgid "Stock Export Options" msgstr "" -#: stock/views.py:243 +#: stock/views.py:264 msgid "Stock Item QR Code" msgstr "" -#: stock/views.py:266 +#: stock/views.py:287 msgid "Adjust Stock" msgstr "" -#: stock/views.py:375 +#: stock/views.py:396 msgid "Move Stock Items" msgstr "" -#: stock/views.py:376 +#: stock/views.py:397 msgid "Count Stock Items" msgstr "" -#: stock/views.py:377 +#: stock/views.py:398 msgid "Remove From Stock" msgstr "" -#: stock/views.py:378 +#: stock/views.py:399 msgid "Add Stock Items" msgstr "" -#: stock/views.py:379 +#: stock/views.py:400 msgid "Delete Stock Items" msgstr "" -#: stock/views.py:407 +#: stock/views.py:428 msgid "Must enter integer value" msgstr "" -#: stock/views.py:412 +#: stock/views.py:433 msgid "Quantity must be positive" msgstr "" -#: stock/views.py:419 +#: stock/views.py:440 #, python-brace-format msgid "Quantity must not exceed {x}" msgstr "" -#: stock/views.py:427 +#: stock/views.py:448 msgid "Confirm stock adjustment" msgstr "" -#: stock/views.py:498 +#: stock/views.py:519 #, python-brace-format msgid "Added stock to {n} items" msgstr "" -#: stock/views.py:513 +#: stock/views.py:534 #, python-brace-format msgid "Removed stock from {n} items" msgstr "" -#: stock/views.py:526 +#: stock/views.py:547 #, python-brace-format msgid "Counted stock for {n} items" msgstr "" -#: stock/views.py:554 +#: stock/views.py:575 msgid "No items were moved" msgstr "" -#: stock/views.py:557 +#: stock/views.py:578 #, python-brace-format msgid "Moved {n} items to {dest}" msgstr "" -#: stock/views.py:576 +#: stock/views.py:597 #, python-brace-format msgid "Deleted {n} stock items" msgstr "" -#: stock/views.py:588 +#: stock/views.py:609 msgid "Edit Stock Item" msgstr "" -#: stock/views.py:624 +#: stock/views.py:645 msgid "Create new Stock Location" msgstr "" -#: stock/views.py:645 +#: stock/views.py:666 msgid "Serialize Stock" msgstr "" -#: stock/views.py:725 +#: stock/views.py:746 msgid "Create new Stock Item" msgstr "" -#: stock/views.py:789 +#: stock/views.py:810 msgid "Copy Stock Item" msgstr "" -#: stock/views.py:839 +#: stock/views.py:860 msgid "Invalid quantity" msgstr "" -#: stock/views.py:842 +#: stock/views.py:863 msgid "Invalid part selection" msgstr "" -#: stock/views.py:904 +#: stock/views.py:925 msgid "Created new stock item" msgstr "" -#: stock/views.py:921 +#: stock/views.py:942 msgid "Delete Stock Location" msgstr "" -#: stock/views.py:934 +#: stock/views.py:955 msgid "Delete Stock Item" msgstr "" -#: stock/views.py:945 +#: stock/views.py:966 msgid "Delete Stock Tracking Entry" msgstr "" -#: stock/views.py:962 +#: stock/views.py:983 msgid "Edit Stock Tracking Entry" msgstr "" -#: stock/views.py:971 +#: stock/views.py:992 msgid "Add Stock Tracking Entry" msgstr "" + +#: templates/about.html:18 +msgid "InvenTree Version Information" +msgstr "" + +#: templates/about.html:21 +msgid "Version" +msgstr "" + +#: templates/about.html:24 +msgid "Commit Hash" +msgstr "" + +#: templates/about.html:27 +msgid "Commit Date" +msgstr "" + +#: templates/about.html:33 +msgid "InvenTree Documentation" +msgstr "" + +#: templates/about.html:37 +msgid "View Code on GitHub" +msgstr "" diff --git a/InvenTree/order/migrations/0015_auto_20200201_2346.py b/InvenTree/order/migrations/0015_auto_20200201_2346.py new file mode 100644 index 0000000000..3407420fc4 --- /dev/null +++ b/InvenTree/order/migrations/0015_auto_20200201_2346.py @@ -0,0 +1,19 @@ +# Generated by Django 2.2.9 on 2020-02-01 23:46 + +from django.db import migrations +import markdownx.models + + +class Migration(migrations.Migration): + + dependencies = [ + ('order', '0014_auto_20191118_2328'), + ] + + operations = [ + migrations.AlterField( + model_name='purchaseorder', + name='notes', + field=markdownx.models.MarkdownxField(blank=True, help_text='Order notes'), + ), + ] diff --git a/InvenTree/order/models.py b/InvenTree/order/models.py index c0be887fe1..b5538c6040 100644 --- a/InvenTree/order/models.py +++ b/InvenTree/order/models.py @@ -12,6 +12,8 @@ from django.contrib.auth.models import User from django.urls import reverse from django.utils.translation import ugettext as _ +from markdownx.models import MarkdownxField + from datetime import datetime from stock.models import StockItem @@ -81,7 +83,7 @@ class Order(models.Model): complete_date = models.DateField(blank=True, null=True) - notes = models.TextField(blank=True, help_text=_('Order notes')) + notes = MarkdownxField(blank=True, help_text=_('Order notes')) def place_order(self): """ Marks the order as PLACED. Order must be currently PENDING. """ diff --git a/InvenTree/order/templates/order/order_base.html b/InvenTree/order/templates/order/order_base.html new file mode 100644 index 0000000000..2cefeb6465 --- /dev/null +++ b/InvenTree/order/templates/order/order_base.html @@ -0,0 +1,132 @@ +{% extends "base.html" %} + +{% load i18n %} +{% load static %} +{% load inventree_extras %} + +{% block page_title %} +InvenTree | {{ order }} +{% endblock %} + +{% block content %} + +
+
+
+
+ +
+
+

{{ order }}

+

{{ order.description }}

+ {% if order.URL %} + {{ order.URL }} + {% endif %} +

+

+
+ + + {% if order.status == OrderStatus.PENDING and order.lines.count > 0 %} + + {% elif order.status == OrderStatus.PLACED %} + + + {% endif %} + {% if order.status == OrderStatus.PENDING or order.status == OrderStatus.PLACED %} + + {% endif %} +
+
+

+
+
+
+
+

{% trans "Purchase Order Details" %}

+ + + + + + + + + + + + + + {% if order.issue_date %} + + + + + {% endif %} + {% if order.status == OrderStatus.COMPLETE %} + + + + + {% endif %} +
{% trans "Supplier" %}{{ order.supplier }}
{% trans "Status" %}{% include "order/order_status.html" %}
{% trans "Created" %}{{ order.creation_date }}{{ order.created_by }}
{% trans "Issued" %}{{ order.issue_date }}
{% trans "Received" %}{{ order.complete_date }}{{ order.received_by }}
+
+
+ +
+
+{% block details %} + + + +{% endblock %} +
+ +{% endblock %} + +{% block js_ready %} +{{ block.super }} + +{% if order.status == OrderStatus.PENDING and order.lines.count > 0 %} +$("#place-order").click(function() { + launchModalForm("{% url 'purchase-order-issue' order.id %}", + { + reload: true, + }); +}); +{% endif %} + +$("#edit-order").click(function() { + launchModalForm("{% url 'purchase-order-edit' order.id %}", + { + reload: true, + } + ); +}); + +$("#cancel-order").click(function() { + launchModalForm("{% url 'purchase-order-cancel' order.id %}", { + reload: true, + }); +}); + + +{% endblock %} \ No newline at end of file diff --git a/InvenTree/order/templates/order/order_notes.html b/InvenTree/order/templates/order/order_notes.html new file mode 100644 index 0000000000..9077108510 --- /dev/null +++ b/InvenTree/order/templates/order/order_notes.html @@ -0,0 +1,57 @@ +{% extends "order/order_base.html" %} + +{% load inventree_extras %} +{% load i18n %} +{% load static %} +{% load markdownify %} + +{% block details %} + +{% include 'order/tabs.html' with tab='notes' %} + +{% if editing %} +

{% trans "Order Notes" %}

+
+ +
+ {% csrf_token %} + + {{ form }} +
+ +
+ +{{ form.media }} + +{% else %} +
+
+

{% trans "Order Notes" %}

+
+
+ +
+
+
+
+
+ {{ order.notes | markdownify }} +
+
+ +{% endif %} + +{% endblock %} + +{% block js_ready %} + +{{ block.super }} + +{% if editing %} +{% else %} +$("#edit-notes").click(function() { + location.href = "{% url 'purchase-order-notes' order.id %}?edit=1"; +}); +{% endif %} + +{% endblock %} \ No newline at end of file diff --git a/InvenTree/order/templates/order/purchase_order_detail.html b/InvenTree/order/templates/order/purchase_order_detail.html index d7d34103b1..15bc55a3d8 100644 --- a/InvenTree/order/templates/order/purchase_order_detail.html +++ b/InvenTree/order/templates/order/purchase_order_detail.html @@ -1,104 +1,22 @@ -{% extends "base.html" %} +{% extends "order/order_base.html" %} +{% load inventree_extras %} {% load i18n %} {% load static %} -{% load inventree_extras %} -{% block page_title %} -InvenTree | {{ order }} -{% endblock %} +{% block details %} -{% block content %} -
-
-
-
- -
-
-

{{ order }}

-

{{ order.description }}

- {% if order.URL %} - {{ order.URL }} - {% endif %} -

-

-
- - - {% if order.status == OrderStatus.PENDING and order.lines.count > 0 %} - - {% elif order.status == OrderStatus.PLACED %} - - - {% endif %} - {% if order.status == OrderStatus.PENDING or order.status == OrderStatus.PLACED %} - - {% endif %} -
-
-

-
-
-
-
-

{% trans "Purchase Order Details" %}

- - - - - - - - - - - - - - {% if order.issue_date %} - - - - - {% endif %} - {% if order.status == OrderStatus.COMPLETE %} - - - - - {% endif %} -
{% trans "Supplier" %}{{ order.supplier }}
{% trans "Status" %}{% include "order/order_status.html" %}
{% trans "Created" %}{{ order.creation_date }}{{ order.created_by }}
{% trans "Issued" %}{{ order.issue_date }}
{% trans "Received" %}{{ order.complete_date }}{{ order.received_by }}
-
-
+{% include 'order/tabs.html' with tab='details' %}
{% if order.status == OrderStatus.PENDING %} - + {% endif %}
-

Order Items

+

{% trans "Order Items" %}

@@ -162,40 +80,11 @@ InvenTree | {{ order }}
-{% if order.notes %} -
-
-
{% trans "Notes" %}
-
{{ order.notes }}
-
-{% endif %} - {% endblock %} {% block js_ready %} -{% if order.status == OrderStatus.PENDING and order.lines.count > 0 %} -$("#place-order").click(function() { - launchModalForm("{% url 'purchase-order-issue' order.id %}", - { - reload: true, - }); -}); -{% endif %} - -$("#edit-order").click(function() { - launchModalForm("{% url 'purchase-order-edit' order.id %}", - { - reload: true, - } - ); -}); - -$("#cancel-order").click(function() { - launchModalForm("{% url 'purchase-order-cancel' order.id %}", { - reload: true, - }); -}); +{{ block.super }} $("#po-lines-table").on('click', ".line-receive", function() { diff --git a/InvenTree/order/templates/order/tabs.html b/InvenTree/order/templates/order/tabs.html new file mode 100644 index 0000000000..e673a3271e --- /dev/null +++ b/InvenTree/order/templates/order/tabs.html @@ -0,0 +1,10 @@ +{% load i18n %} + + diff --git a/InvenTree/order/urls.py b/InvenTree/order/urls.py index d30879cf8e..d1d7d7f5f7 100644 --- a/InvenTree/order/urls.py +++ b/InvenTree/order/urls.py @@ -19,6 +19,8 @@ purchase_order_detail_urls = [ url(r'^export/?', views.PurchaseOrderExport.as_view(), name='purchase-order-export'), + url(r'^notes/', views.PurchaseOrderNotes.as_view(), name='purchase-order-notes'), + url(r'^.*$', views.PurchaseOrderDetail.as_view(), name='purchase-order-detail'), ] diff --git a/InvenTree/order/views.py b/InvenTree/order/views.py index 7b445fbea3..bb1702c8a2 100644 --- a/InvenTree/order/views.py +++ b/InvenTree/order/views.py @@ -7,8 +7,9 @@ from __future__ import unicode_literals from django.db import transaction from django.shortcuts import get_object_or_404 +from django.urls import reverse from django.utils.translation import ugettext as _ -from django.views.generic import DetailView, ListView +from django.views.generic import DetailView, ListView, UpdateView from django.forms import HiddenInput import logging @@ -69,6 +70,28 @@ class PurchaseOrderDetail(DetailView): return ctx +class PurchaseOrderNotes(UpdateView): + """ View for updating the 'notes' field of a PurchaseOrder """ + + context_object_name = 'order' + template_name = 'order/order_notes.html' + model = PurchaseOrder + + fields = ['notes'] + + def get_success_url(self): + + return reverse('purchase-order-notes', kwargs={'pk': self.get_object().id}) + + def get_context_data(self, **kwargs): + + ctx = super().get_context_data(**kwargs) + + ctx['editing'] = str2bool(self.request.GET.get('edit', '')) + + return ctx + + class PurchaseOrderCreate(AjaxCreateView): """ View for creating a new PurchaseOrder object using a modal form """ diff --git a/InvenTree/part/admin.py b/InvenTree/part/admin.py index fcef36a772..20ad569a12 100644 --- a/InvenTree/part/admin.py +++ b/InvenTree/part/admin.py @@ -69,7 +69,7 @@ class PartResource(ModelResource): class PartAdmin(ImportExportModelAdmin): - + resource_class = PartResource list_display = ('full_name', 'description', 'total_stock', 'category') diff --git a/InvenTree/part/forms.py b/InvenTree/part/forms.py index 339c8519fc..7a4eecd583 100644 --- a/InvenTree/part/forms.py +++ b/InvenTree/part/forms.py @@ -104,7 +104,6 @@ class EditPartForm(HelperForm): 'default_supplier', 'units', 'minimum_stock', - 'notes', 'active', ] diff --git a/InvenTree/part/migrations/0026_auto_20200131_1022.py b/InvenTree/part/migrations/0026_auto_20200131_1022.py new file mode 100644 index 0000000000..f3a3af73a4 --- /dev/null +++ b/InvenTree/part/migrations/0026_auto_20200131_1022.py @@ -0,0 +1,19 @@ +# Generated by Django 2.2.9 on 2020-01-31 10:22 + +from django.db import migrations +import markdownx.models + + +class Migration(migrations.Migration): + + dependencies = [ + ('part', '0025_auto_20191118_2316'), + ] + + operations = [ + migrations.AlterField( + model_name='part', + name='notes', + field=markdownx.models.MarkdownxField(help_text='Part notes - supports Markdown formatting'), + ), + ] diff --git a/InvenTree/part/models.py b/InvenTree/part/models.py index 386bf3e2c9..2df55ad73b 100644 --- a/InvenTree/part/models.py +++ b/InvenTree/part/models.py @@ -22,6 +22,8 @@ from django.contrib.auth.models import User from django.db.models.signals import pre_delete from django.dispatch import receiver +from markdownx.models import MarkdownxField + from mptt.models import TreeForeignKey from datetime import datetime @@ -422,7 +424,7 @@ class Part(models.Model): virtual = models.BooleanField(default=False, help_text=_('Is this a virtual part, such as a software product or license?')) - notes = models.TextField(blank=True) + notes = MarkdownxField(help_text=_('Part notes - supports Markdown formatting')) bom_checksum = models.CharField(max_length=128, blank=True, help_text=_('Stored BOM checksum')) diff --git a/InvenTree/part/templates/markdownx/widget.html b/InvenTree/part/templates/markdownx/widget.html new file mode 100644 index 0000000000..61c8673748 --- /dev/null +++ b/InvenTree/part/templates/markdownx/widget.html @@ -0,0 +1,10 @@ +{% load i18n %} + +
+
+ {% include 'django/forms/widgets/textarea.html' %} +
+
+
+
+
\ No newline at end of file diff --git a/InvenTree/part/templates/part/allocation.html b/InvenTree/part/templates/part/allocation.html index 21c3413ea0..c87d71814b 100644 --- a/InvenTree/part/templates/part/allocation.html +++ b/InvenTree/part/templates/part/allocation.html @@ -3,10 +3,8 @@ {% include "part/tabs.html" with tab="allocation" %} -

Part Allocation

+

Part Allocation

-{% if part.allocated_build_count > 0 %} -

Allocated to Part Builds

@@ -23,7 +21,6 @@ {% endfor %}
Build
-{% endif %} {% endblock %} diff --git a/InvenTree/part/templates/part/attachments.html b/InvenTree/part/templates/part/attachments.html index 1f35535fcd..88cb965eeb 100644 --- a/InvenTree/part/templates/part/attachments.html +++ b/InvenTree/part/templates/part/attachments.html @@ -1,17 +1,17 @@ {% extends "part/part_base.html" %} {% load static %} - +{% load i18n %} {% block details %} {% include 'part/tabs.html' with tab='attachments' %} -

Part Attachments

+

{% trans "Part Attachments" %}


- +
@@ -19,8 +19,8 @@ - - + + @@ -31,10 +31,10 @@
FileComment{% trans "File" %}{% trans "Comment" %}
{{ attachment.comment }}
- -
diff --git a/InvenTree/part/templates/part/detail.html b/InvenTree/part/templates/part/detail.html index 12db3e3e9b..a37ad5823d 100644 --- a/InvenTree/part/templates/part/detail.html +++ b/InvenTree/part/templates/part/detail.html @@ -147,13 +147,6 @@ -{% if part.notes %} -
-
{% trans "Notes" %}
-
{{ part.notes }}
-
-{% endif %} - {% endblock %} {% block js_load %} diff --git a/InvenTree/part/templates/part/notes.html b/InvenTree/part/templates/part/notes.html new file mode 100644 index 0000000000..4aace0fdae --- /dev/null +++ b/InvenTree/part/templates/part/notes.html @@ -0,0 +1,56 @@ +{% extends "part/part_base.html" %} +{% load static %} +{% load crispy_forms_tags %} +{% load i18n %} +{% load markdownify %} + +{% block details %} + +{% include 'part/tabs.html' with tab='notes' %} + + +{% if editing %} +

{% trans "Part Notes" %}

+
+
+ {% csrf_token %} + + {{ form }} +
+ + +
+ +{{ form.media }} + +{% else %} +
+
+

{% trans "Part Notes" %}

+
+
+ +
+
+
+
+
+ {{ part.notes | markdownify }} +
+
+ +{% endif %} + +{% endblock %} + +{% block js_ready %} +{{ block.super }} + +{% if editing %} +{% else %} +$("#edit-notes").click(function() { + location.href = "{% url 'part-notes' part.id %}?edit=1"; +}); +{% endif %} + +{% endblock %} \ No newline at end of file diff --git a/InvenTree/part/templates/part/tabs.html b/InvenTree/part/templates/part/tabs.html index 52630d333f..717918e542 100644 --- a/InvenTree/part/templates/part/tabs.html +++ b/InvenTree/part/templates/part/tabs.html @@ -54,4 +54,7 @@ {% trans "Attachments" %} {% if part.attachment_count > 0 %}{{ part.attachment_count }}{% endif %} + + {% trans "Notes" %}{% if part.notes %} {% endif %} + \ No newline at end of file diff --git a/InvenTree/part/templatetags/inventree_extras.py b/InvenTree/part/templatetags/inventree_extras.py index d0497c28e4..323d65050e 100644 --- a/InvenTree/part/templatetags/inventree_extras.py +++ b/InvenTree/part/templatetags/inventree_extras.py @@ -48,11 +48,17 @@ def inventree_version(*args, **kwargs): @register.simple_tag() -def inventree_commit(*args, **kwargs): +def inventree_commit_hash(*args, **kwargs): """ Return InvenTree git commit hash string """ return version.inventreeCommitHash() +@register.simple_tag() +def inventree_commit_date(*args, **kwargs): + """ Return InvenTree git commit date string """ + return version.inventreeCommitDate() + + @register.simple_tag() def inventree_github_url(*args, **kwargs): """ Return URL for InvenTree github site """ diff --git a/InvenTree/part/test_part.py b/InvenTree/part/test_part.py index 46eb484b12..28ee93d976 100644 --- a/InvenTree/part/test_part.py +++ b/InvenTree/part/test_part.py @@ -22,9 +22,13 @@ class TemplateTagTest(TestCase): self.assertEqual(type(inventree_extras.inventree_version()), str) def test_hash(self): - hash = inventree_extras.inventree_commit() + hash = inventree_extras.inventree_commit_hash() self.assertEqual(len(hash), 7) + def test_date(self): + d = inventree_extras.inventree_commit_date() + self.assertEqual(len(d.split('-')), 3) + def test_github(self): self.assertIn('github.com', inventree_extras.inventree_github_url()) diff --git a/InvenTree/part/urls.py b/InvenTree/part/urls.py index bbad7634c5..0a9adefe8f 100644 --- a/InvenTree/part/urls.py +++ b/InvenTree/part/urls.py @@ -52,6 +52,7 @@ part_detail_urls = [ url(r'^orders/?', views.PartDetail.as_view(template_name='part/orders.html'), name='part-orders'), url(r'^track/?', views.PartDetail.as_view(template_name='part/track.html'), name='part-track'), url(r'^attachments/?', views.PartDetail.as_view(template_name='part/attachments.html'), name='part-attachments'), + url(r'^notes/?', views.PartNotes.as_view(), name='part-notes'), url(r'^qr_code/?', views.PartQRCode.as_view(), name='part-qr'), diff --git a/InvenTree/part/views.py b/InvenTree/part/views.py index 6d4eb5203b..925e9ce48a 100644 --- a/InvenTree/part/views.py +++ b/InvenTree/part/views.py @@ -11,7 +11,7 @@ from django.shortcuts import get_object_or_404 from django.shortcuts import HttpResponseRedirect from django.utils.translation import gettext_lazy as _ from django.urls import reverse, reverse_lazy -from django.views.generic import DetailView, ListView, FormView +from django.views.generic import DetailView, ListView, FormView, UpdateView from django.forms.models import model_to_dict from django.forms import HiddenInput, CheckboxInput @@ -519,6 +519,39 @@ class PartCreate(AjaxCreateView): return initials +class PartNotes(UpdateView): + """ View for editing the 'notes' field of a Part object. + Presents a live markdown editor. + """ + + context_object_name = 'part' + # form_class = part_forms.EditNotesForm + template_name = 'part/notes.html' + model = Part + + fields = ['notes'] + + def get_success_url(self): + """ Return the success URL for this form """ + + return reverse('part-notes', kwargs={'pk': self.get_object().id}) + + def get_context_data(self, **kwargs): + + part = self.get_object() + + ctx = super().get_context_data(**kwargs) + + ctx['editing'] = str2bool(self.request.GET.get('edit', '')) + + ctx['starred'] = part.isStarredBy(self.request.user) + ctx['disabled'] = not part.active + + ctx['OrderStatus'] = OrderStatus + + return ctx + + class PartDetail(DetailView): """ Detail view for Part object """ diff --git a/InvenTree/stock/forms.py b/InvenTree/stock/forms.py index 8145a17f89..5c84f3b4df 100644 --- a/InvenTree/stock/forms.py +++ b/InvenTree/stock/forms.py @@ -162,7 +162,6 @@ class EditStockItemForm(HelperForm): 'serial', 'batch', 'status', - 'notes', 'URL', 'delete_on_deplete', ] diff --git a/InvenTree/stock/migrations/0018_auto_20200202_0103.py b/InvenTree/stock/migrations/0018_auto_20200202_0103.py new file mode 100644 index 0000000000..9cf90ceebe --- /dev/null +++ b/InvenTree/stock/migrations/0018_auto_20200202_0103.py @@ -0,0 +1,19 @@ +# Generated by Django 2.2.9 on 2020-02-02 01:03 + +from django.db import migrations +import markdownx.models + + +class Migration(migrations.Migration): + + dependencies = [ + ('stock', '0017_auto_20191118_2311'), + ] + + operations = [ + migrations.AlterField( + model_name='stockitem', + name='notes', + field=markdownx.models.MarkdownxField(blank=True, help_text='Stock Item Notes'), + ), + ] diff --git a/InvenTree/stock/models.py b/InvenTree/stock/models.py index 1122d4326c..d0bc23f14d 100644 --- a/InvenTree/stock/models.py +++ b/InvenTree/stock/models.py @@ -16,6 +16,8 @@ from django.contrib.auth.models import User from django.db.models.signals import pre_delete from django.dispatch import receiver +from markdownx.models import MarkdownxField + from mptt.models import TreeForeignKey from decimal import Decimal, InvalidOperation @@ -358,7 +360,7 @@ class StockItem(models.Model): choices=StockStatus.items(), validators=[MinValueValidator(0)]) - notes = models.CharField(max_length=250, blank=True, help_text=_('Stock Item Notes')) + notes = MarkdownxField(blank=True, help_text=_('Stock Item Notes')) # If stock item is incoming, an (optional) ETA field # expected_arrival = models.DateField(null=True, blank=True) diff --git a/InvenTree/stock/templates/stock/item.html b/InvenTree/stock/templates/stock/item.html index f6494edd93..38c1d7dcac 100644 --- a/InvenTree/stock/templates/stock/item.html +++ b/InvenTree/stock/templates/stock/item.html @@ -1,160 +1,12 @@ -{% extends "stock/stock_app_base.html" %} +{% extends "stock/item_base.html" %} + {% load static %} {% load inventree_extras %} {% load i18n %} -{% block content %} -
-
-

{% trans "Stock Item Details" %}

- {% if item.serialized %} -

{{ item.part.full_name}} # {{ item.serial }}

- {% else %} -

{{ item.quantity }} × {{ item.part.full_name }}

- {% endif %} -

-

- {% include "qr_button.html" %} - {% if item.in_stock %} - {% if not item.serialized %} - - - - {% if item.part.trackable %} - - {% endif %} - {% endif %} - - - {% endif %} - - -
-

- {% if item.serialized %} -
- {% trans "This stock item is serialized - it has a unique serial number and the quantity cannot be adjusted." %} -
- {% elif item.delete_on_deplete %} -
- {% trans "This stock item will be automatically deleted when all stock is depleted." %} -
- {% endif %} -
+{% block details %} -
-
- - - - - - {% if item.belongs_to %} - - - - - {% elif item.location %} - - - - - {% endif %} - {% if item.serialized %} - - - - - {% else %} - - - - - {% endif %} - {% if item.batch %} - - - - - {% endif %} - {% if item.build %} - - - - - {% endif %} - {% if item.purchase_order %} - - - - - {% endif %} - {% if item.customer %} - - - - - {% endif %} - {% if item.URL %} - - - - - {% endif %} - {% if item.supplier_part %} - - - - - - - - - {% endif %} - - - - - - - {% if item.stocktake_date %} - - {% else %} - - {% endif %} - - - - - - {% if item.notes %} - - - - - {% endif %} -
Part - {% include "hover_image.html" with image=item.part.image hover=True %} - {{ item.part.full_name }} -
{% trans "Belongs To" %}{{ item.belongs_to }}
{% trans "Location" %}{{ item.location.name }}
{% trans "Serial Number" %}{{ item.serial }}
{% trans "Quantity" %}{% decimal item.quantity %} {% if item.part.units %}{{ item.part.units }}{% endif %}
{% trans "Batch" %}{{ item.batch }}
{% trans "Build" %}{{ item.build }}
{% trans "Purchase Order" %}{{ item.purchase_order }}
{% trans "Customer" %}{{ item.customer.name }}
{% trans "URL" %}{{ item.URL }}
{% trans "Supplier" %}{{ item.supplier_part.supplier.name }}
{% trans "Supplier Part" %}{{ item.supplier_part.SKU }}
{% trans "Last Updated" %}{{ item.updated }}
{% trans "Last Stocktake" %}{{ item.stocktake_date }} {{ item.stocktake_user }}{% trans "No stocktake performed" %}
{% trans "Status" %}{{ item.get_status_display }}
{% trans "Notes" %}{{ item.notes }}
-
-
+{% include "stock/tabs.html" with tab="tracking" %}

{% trans "Stock Tracking Information" %}

@@ -167,6 +19,7 @@
{% endblock %} + {% block js_ready %} {{ block.super }} @@ -179,84 +32,6 @@ ); }); - $("#stock-serialize").click(function() { - launchModalForm( - "{% url 'stock-item-serialize' item.id %}", - { - reload: true, - } - ); - }); - - $("#stock-duplicate").click(function() { - launchModalForm( - "{% url 'stock-item-create' %}", - { - follow: true, - data: { - copy: {{ item.id }}, - }, - } - ); - }); - - $("#stock-edit").click(function () { - launchModalForm( - "{% url 'stock-item-edit' item.id %}", - { - reload: true, - submit_text: "Save", - } - ); - }); - - $("#show-qr-code").click(function() { - launchModalForm("{% url 'stock-item-qr' item.id %}", - { - no_post: true, - }); - }); - - {% if item.in_stock %} - - function itemAdjust(action) { - launchModalForm("/stock/adjust/", - { - data: { - action: action, - item: {{ item.id }}, - }, - reload: true, - follow: true, - } - ); - } - - $("#stock-move").click(function() { - itemAdjust("move"); - }); - - $("#stock-count").click(function() { - itemAdjust('count'); - }); - - $('#stock-remove').click(function() { - itemAdjust('take'); - }); - - $('#stock-add').click(function() { - itemAdjust('add'); - }); - - {% endif %} - - $("#stock-delete").click(function () { - launchModalForm( - "{% url 'stock-item-delete' item.id %}", - { - redirect: "{% url 'part-stock' item.part.id %}" - }); - }); loadStockTrackingTable($("#track-table"), { params: function(p) { diff --git a/InvenTree/stock/templates/stock/item_base.html b/InvenTree/stock/templates/stock/item_base.html new file mode 100644 index 0000000000..5caead54a7 --- /dev/null +++ b/InvenTree/stock/templates/stock/item_base.html @@ -0,0 +1,247 @@ +{% extends "stock/stock_app_base.html" %} +{% load static %} +{% load inventree_extras %} +{% load i18n %} +{% block content %} + + +
+
+

{% trans "Stock Item Details" %}

+ {% if item.serialized %} +

{{ item.part.full_name}} # {{ item.serial }}

+ {% else %} +

{{ item.quantity }} × {{ item.part.full_name }}

+ {% endif %} +

+

+ {% include "qr_button.html" %} + {% if item.in_stock %} + {% if not item.serialized %} + + + + {% if item.part.trackable %} + + {% endif %} + {% endif %} + + + {% endif %} + + +
+

+ {% if item.serialized %} +
+ {% trans "This stock item is serialized - it has a unique serial number and the quantity cannot be adjusted." %} +
+ {% elif item.delete_on_deplete %} +
+ {% trans "This stock item will be automatically deleted when all stock is depleted." %} +
+ {% endif %} +
+ +
+
+ + + + + + {% if item.belongs_to %} + + + + + {% elif item.location %} + + + + + {% endif %} + {% if item.serialized %} + + + + + {% else %} + + + + + {% endif %} + {% if item.batch %} + + + + + {% endif %} + {% if item.build %} + + + + + {% endif %} + {% if item.purchase_order %} + + + + + {% endif %} + {% if item.customer %} + + + + + {% endif %} + {% if item.URL %} + + + + + {% endif %} + {% if item.supplier_part %} + + + + + + + + + {% endif %} + + + + + + + {% if item.stocktake_date %} + + {% else %} + + {% endif %} + + + + + +
Part + {% include "hover_image.html" with image=item.part.image hover=True %} + {{ item.part.full_name }} +
{% trans "Belongs To" %}{{ item.belongs_to }}
{% trans "Location" %}{{ item.location.name }}
{% trans "Serial Number" %}{{ item.serial }}
{% trans "Quantity" %}{% decimal item.quantity %} {% if item.part.units %}{{ item.part.units }}{% endif %}
{% trans "Batch" %}{{ item.batch }}
{% trans "Build" %}{{ item.build }}
{% trans "Purchase Order" %}{{ item.purchase_order }}
{% trans "Customer" %}{{ item.customer.name }}
{% trans "URL" %}{{ item.URL }}
{% trans "Supplier" %}{{ item.supplier_part.supplier.name }}
{% trans "Supplier Part" %}{{ item.supplier_part.SKU }}
{% trans "Last Updated" %}{{ item.updated }}
{% trans "Last Stocktake" %}{{ item.stocktake_date }} {{ item.stocktake_user }}{% trans "No stocktake performed" %}
{% trans "Status" %}{{ item.get_status_display }}
+
+
+ + +
+
+{% block details %} + +{% endblock %} +
+ +{% endblock %} + +{% block js_ready %} + +{{ block.super }} + +$("#stock-serialize").click(function() { + launchModalForm( + "{% url 'stock-item-serialize' item.id %}", + { + reload: true, + } + ); +}); + +$("#stock-duplicate").click(function() { + launchModalForm( + "{% url 'stock-item-create' %}", + { + follow: true, + data: { + copy: {{ item.id }}, + }, + } + ); +}); + +$("#stock-edit").click(function () { + launchModalForm( + "{% url 'stock-item-edit' item.id %}", + { + reload: true, + submit_text: "Save", + } + ); +}); + +$("#show-qr-code").click(function() { + launchModalForm("{% url 'stock-item-qr' item.id %}", + { + no_post: true, + }); +}); + +{% if item.in_stock %} + +function itemAdjust(action) { + launchModalForm("/stock/adjust/", + { + data: { + action: action, + item: {{ item.id }}, + }, + reload: true, + follow: true, + } + ); +} + +$("#stock-move").click(function() { + itemAdjust("move"); +}); + +$("#stock-count").click(function() { + itemAdjust('count'); +}); + +$('#stock-remove').click(function() { + itemAdjust('take'); +}); + +$('#stock-add').click(function() { + itemAdjust('add'); +}); + +{% endif %} + +$("#stock-delete").click(function () { + launchModalForm( + "{% url 'stock-item-delete' item.id %}", + { + redirect: "{% url 'part-stock' item.part.id %}" + }); +}); + +{% endblock %} diff --git a/InvenTree/stock/templates/stock/item_notes.html b/InvenTree/stock/templates/stock/item_notes.html new file mode 100644 index 0000000000..a5abd13781 --- /dev/null +++ b/InvenTree/stock/templates/stock/item_notes.html @@ -0,0 +1,57 @@ +{% extends "stock/item_base.html" %} + +{% load static %} +{% load inventree_extras %} +{% load i18n %} +{% load markdownify %} + +{% block details %} + +{% include "stock/tabs.html" with tab="notes" %} + +{% if editing %} +

{% trans "Stock Item Notes" %}

+
+ +
+ {% csrf_token %} + + {{ form }} +
+ +
+ +{{ form.media }} + +{% else %} +
+
+

{% trans "Stock Item Notes" %}

+
+
+ +
+
+
+
+
+ {{ item.notes | markdownify }} +
+
+ +{% endif %} + +{% endblock %} + +{% block js_ready %} + +{{ block.super }} + +{% if editing %} +{% else %} +$("#edit-notes").click(function() { + location.href = "{% url 'stock-item-notes' item.id %}?edit=1"; +}); +{% endif %} + +{% endblock %} \ No newline at end of file diff --git a/InvenTree/stock/templates/stock/tabs.html b/InvenTree/stock/templates/stock/tabs.html new file mode 100644 index 0000000000..ac381a76ab --- /dev/null +++ b/InvenTree/stock/templates/stock/tabs.html @@ -0,0 +1,16 @@ +{% load i18n %} + + \ No newline at end of file diff --git a/InvenTree/stock/urls.py b/InvenTree/stock/urls.py index fa849211f3..50ac170ce3 100644 --- a/InvenTree/stock/urls.py +++ b/InvenTree/stock/urls.py @@ -24,6 +24,8 @@ stock_item_detail_urls = [ url(r'^add_tracking/', views.StockItemTrackingCreate.as_view(), name='stock-tracking-create'), + url(r'^notes/', views.StockItemNotes.as_view(), name='stock-item-notes'), + url('^.*$', views.StockItemDetail.as_view(), name='stock-item-detail'), ] diff --git a/InvenTree/stock/views.py b/InvenTree/stock/views.py index dc56aa87ff..cb478e42f3 100644 --- a/InvenTree/stock/views.py +++ b/InvenTree/stock/views.py @@ -7,7 +7,7 @@ from __future__ import unicode_literals from django.core.exceptions import ValidationError from django.views.generic.edit import FormMixin -from django.views.generic import DetailView, ListView +from django.views.generic import DetailView, ListView, UpdateView from django.forms.models import model_to_dict from django.forms import HiddenInput from django.urls import reverse @@ -83,6 +83,27 @@ class StockItemDetail(DetailView): model = StockItem +class StockItemNotes(UpdateView): + """ View for editing the 'notes' field of a StockItem object """ + + context_object_name = 'item' + template_name = 'stock/item_notes.html' + model = StockItem + + fields = ['notes'] + + def get_success_url(self): + return reverse('stock-item-notes', kwargs={'pk': self.get_object().id}) + + def get_context_data(self, **kwargs): + + ctx = super().get_context_data(**kwargs) + + ctx['editing'] = str2bool(self.request.GET.get('edit', '')) + + return ctx + + class StockLocationEdit(AjaxUpdateView): """ View for editing details of a StockLocation. diff --git a/InvenTree/templates/about.html b/InvenTree/templates/about.html index 7e2abeb788..4f8d7e6d4e 100644 --- a/InvenTree/templates/about.html +++ b/InvenTree/templates/about.html @@ -1,5 +1,6 @@ {% load static %} {% load inventree_extras %} +{% load i18n %}