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" %}
- 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 %}
{% if build.batch %}
- Batch {{ build.batch }}
+ {% trans "Batch" %} {{ build.batch }}
{% endif %}
{% if build.URL %}
- URL {{ build.URL }}
+ {% trans "URL" %} {{ build.URL }}
{% endif %}
- Created {{ build.creation_date }}
+ {% trans "Created" %} {{ build.creation_date }}
{% if build.is_active %}
- Enough Parts?
+ {% trans "Enough Parts?" %}
{% if build.can_build %}
- Yes
+ {% trans "Yes" %}
{% else %}
- No
+ {% trans "No" %}
{% endif %}
{% endif %}
{% if build.completion_date %}
- 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 %}
{% 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" %}
+
+
+
+{{ 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" %}
+
+
+
+{{ 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 %}
+
+
+
+
+
{% trans "Purchase Order Details" %}
+
+
+ {% trans "Supplier" %}
+ {{ order.supplier }}
+
+
+ {% trans "Status" %}
+ {% include "order/order_status.html" %}
+
+
+ {% trans "Created" %}
+ {{ order.creation_date }}{{ order.created_by }}
+
+ {% if order.issue_date %}
+
+ {% trans "Issued" %}
+ {{ order.issue_date }}
+
+ {% endif %}
+ {% if order.status == OrderStatus.COMPLETE %}
+
+ {% trans "Received" %}
+ {{ order.complete_date }}{{ order.received_by }}
+
+ {% endif %}
+
+
+
+
+
+
+{% 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" %}
+
+
+
+
+{{ 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 %}
-
-
-
-
{% trans "Purchase Order Details" %}
-
-
- {% trans "Supplier" %}
- {{ order.supplier }}
-
-
- {% trans "Status" %}
- {% include "order/order_status.html" %}
-
-
- {% trans "Created" %}
- {{ order.creation_date }}{{ order.created_by }}
-
- {% if order.issue_date %}
-
- {% trans "Issued" %}
- {{ order.issue_date }}
-
- {% endif %}
- {% if order.status == OrderStatus.COMPLETE %}
-
- {% trans "Received" %}
- {{ order.complete_date }}{{ order.received_by }}
-
- {% endif %}
-
-
-
+{% include 'order/tabs.html' with tab='details' %}
{% if order.status == OrderStatus.PENDING %}
- Add Line Item
+ {% trans "Add Line Item" %}
{% 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
Build
@@ -23,7 +21,6 @@
{% endfor %}
-{% 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 @@
- File
- Comment
+ {% trans "File" %}
+ {% trans "Comment" %}
@@ -31,10 +31,10 @@
{{ 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" %}
+
+
+
+{{ 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 %}
-
-
-
-
- Part
-
- {% include "hover_image.html" with image=item.part.image hover=True %}
- {{ item.part.full_name }}
-
-
- {% if item.belongs_to %}
-
- {% trans "Belongs To" %}
- {{ item.belongs_to }}
-
- {% elif item.location %}
-
- {% trans "Location" %}
- {{ item.location.name }}
-
- {% endif %}
- {% if item.serialized %}
-
- {% trans "Serial Number" %}
- {{ item.serial }}
-
- {% else %}
-
- {% trans "Quantity" %}
- {% decimal item.quantity %} {% if item.part.units %}{{ item.part.units }}{% endif %}
-
- {% endif %}
- {% if item.batch %}
-
- {% trans "Batch" %}
- {{ item.batch }}
-
- {% endif %}
- {% if item.build %}
-
- {% trans "Build" %}
- {{ item.build }}
-
- {% endif %}
- {% if item.purchase_order %}
-
- {% trans "Purchase Order" %}
- {{ item.purchase_order }}
-
- {% endif %}
- {% if item.customer %}
-
- {% trans "Customer" %}
- {{ item.customer.name }}
-
- {% endif %}
- {% if item.URL %}
-
- {% trans "URL" %}
- {{ item.URL }}
-
- {% endif %}
- {% if item.supplier_part %}
-
- {% trans "Supplier" %}
- {{ item.supplier_part.supplier.name }}
-
-
- {% trans "Supplier Part" %}
- {{ item.supplier_part.SKU }}
-
- {% endif %}
-
- {% trans "Last Updated" %}
- {{ item.updated }}
-
-
- {% trans "Last Stocktake" %}
- {% if item.stocktake_date %}
- {{ item.stocktake_date }} {{ item.stocktake_user }}
- {% else %}
- {% trans "No stocktake performed" %}
- {% endif %}
-
-
- {% trans "Status" %}
- {{ item.get_status_display }}
-
- {% if item.notes %}
-
- {% trans "Notes" %}
- {{ item.notes }}
-
- {% endif %}
-
-
-
+{% 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 %}
+
+
+
+
+
+
+ Part
+
+ {% include "hover_image.html" with image=item.part.image hover=True %}
+ {{ item.part.full_name }}
+
+
+ {% if item.belongs_to %}
+
+ {% trans "Belongs To" %}
+ {{ item.belongs_to }}
+
+ {% elif item.location %}
+
+ {% trans "Location" %}
+ {{ item.location.name }}
+
+ {% endif %}
+ {% if item.serialized %}
+
+ {% trans "Serial Number" %}
+ {{ item.serial }}
+
+ {% else %}
+
+ {% trans "Quantity" %}
+ {% decimal item.quantity %} {% if item.part.units %}{{ item.part.units }}{% endif %}
+
+ {% endif %}
+ {% if item.batch %}
+
+ {% trans "Batch" %}
+ {{ item.batch }}
+
+ {% endif %}
+ {% if item.build %}
+
+ {% trans "Build" %}
+ {{ item.build }}
+
+ {% endif %}
+ {% if item.purchase_order %}
+
+ {% trans "Purchase Order" %}
+ {{ item.purchase_order }}
+
+ {% endif %}
+ {% if item.customer %}
+
+ {% trans "Customer" %}
+ {{ item.customer.name }}
+
+ {% endif %}
+ {% if item.URL %}
+
+ {% trans "URL" %}
+ {{ item.URL }}
+
+ {% endif %}
+ {% if item.supplier_part %}
+
+ {% trans "Supplier" %}
+ {{ item.supplier_part.supplier.name }}
+
+
+ {% trans "Supplier Part" %}
+ {{ item.supplier_part.SKU }}
+
+ {% endif %}
+
+ {% trans "Last Updated" %}
+ {{ item.updated }}
+
+
+ {% trans "Last Stocktake" %}
+ {% if item.stocktake_date %}
+ {{ item.stocktake_date }} {{ item.stocktake_user }}
+ {% else %}
+ {% trans "No stocktake performed" %}
+ {% endif %}
+
+
+ {% 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" %}
+
+
+
+
+{{ 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 %}