Merge branch 'master' of https://github.com/inventree/InvenTree into part-import

This commit is contained in:
Matthias 2021-05-18 00:57:10 +02:00
commit 46723f42ca
16 changed files with 138 additions and 10 deletions

View File

@ -88,6 +88,11 @@ DEBUG = _is_true(get_setting(
CONFIG.get('debug', True) CONFIG.get('debug', True)
)) ))
DOCKER = _is_true(get_setting(
'INVENTREE_DOCKER',
False
))
# Configure logging settings # Configure logging settings
log_level = get_setting( log_level = get_setting(
'INVENTREE_LOG_LEVEL', 'INVENTREE_LOG_LEVEL',

View File

@ -12,7 +12,7 @@ function attachClipboard(selector, containerselector, textElement) {
return document.getElementById(textElement).textContent; return document.getElementById(textElement).textContent;
} }
} else { } else {
text = function() { text = function(trigger) {
var content = trigger.parentElement.parentElement.textContent;return content.trim(); var content = trigger.parentElement.parentElement.textContent;return content.trim();
} }
} }
@ -22,7 +22,6 @@ function attachClipboard(selector, containerselector, textElement) {
text: text, text: text,
container: containerselector container: containerselector
}); });
console.log(cis);
} }
@ -81,7 +80,6 @@ function inventreeDocReady() {
attachClipboard('.clip-btn'); attachClipboard('.clip-btn');
attachClipboard('.clip-btn', 'modal-about'); // modals attachClipboard('.clip-btn', 'modal-about'); // modals
attachClipboard('.clip-btn-version', 'modal-about', 'about-copy-text'); // version-text attachClipboard('.clip-btn-version', 'modal-about', 'about-copy-text'); // version-text
} }
function isFileTransfer(transfer) { function isFileTransfer(transfer) {

View File

@ -459,8 +459,8 @@ class FileManagementFormView(MultiStepFormView):
if guess: if guess:
n = list(self.column_selections.values()).count(self.column_selections[col]) n = list(self.column_selections.values()).count(self.column_selections[col])
if n > 1: if n > 1 and self.column_selections[col] not in duplicates:
duplicates.append(col) duplicates.append(self.column_selections[col])
# Store extra context data # Store extra context data
self.extra_context_data = { self.extra_context_data = {

View File

@ -13,6 +13,10 @@ from .models import SalesOrder, SalesOrderLineItem
from .models import SalesOrderAllocation from .models import SalesOrderAllocation
class PurchaseOrderLineItemInlineAdmin(admin.StackedInline):
model = PurchaseOrderLineItem
class PurchaseOrderAdmin(ImportExportModelAdmin): class PurchaseOrderAdmin(ImportExportModelAdmin):
list_display = ( list_display = (
@ -29,6 +33,10 @@ class PurchaseOrderAdmin(ImportExportModelAdmin):
'description', 'description',
] ]
inlines = [
PurchaseOrderLineItemInlineAdmin
]
class SalesOrderAdmin(ImportExportModelAdmin): class SalesOrderAdmin(ImportExportModelAdmin):

View File

@ -826,6 +826,9 @@ class SalesOrderAllocation(models.Model):
else: else:
return "" return ""
def get_po(self):
return self.item.purchase_order
def complete_allocation(self, user): def complete_allocation(self, user):
""" """
Complete this allocation (called when the parent SalesOrder is marked as "shipped"): Complete this allocation (called when the parent SalesOrder is marked as "shipped"):

View File

@ -235,6 +235,7 @@ class SalesOrderAllocationSerializer(InvenTreeModelSerializer):
location_path = serializers.CharField(source='get_location_path') location_path = serializers.CharField(source='get_location_path')
location_id = serializers.IntegerField(source='get_location') location_id = serializers.IntegerField(source='get_location')
serial = serializers.CharField(source='get_serial') serial = serializers.CharField(source='get_serial')
po = serializers.CharField(source='get_po')
quantity = serializers.FloatField() quantity = serializers.FloatField()
class Meta: class Meta:
@ -247,6 +248,7 @@ class SalesOrderAllocationSerializer(InvenTreeModelSerializer):
'quantity', 'quantity',
'location_id', 'location_id',
'location_path', 'location_path',
'po',
'item', 'item',
] ]

View File

@ -55,7 +55,7 @@
<td> <td>
{{ col }} {{ col }}
{% for duplicate in duplicates %} {% for duplicate in duplicates %}
{% if duplicate == col.name %} {% if duplicate == col.value %}
<div class='alert alert-danger alert-block text-center' role='alert' style='padding:2px; margin-top:6px; margin-bottom:2px'> <div class='alert alert-danger alert-block text-center' role='alert' style='padding:2px; margin-top:6px; margin-bottom:2px'>
<b>{% trans "Duplicate selection" %}</b> <b>{% trans "Duplicate selection" %}</b>
</div> </div>

View File

@ -87,6 +87,9 @@ function showAllocationSubTable(index, row, element) {
return renderLink(row.location_path, `/stock/location/${row.location_id}/`); return renderLink(row.location_path, `/stock/location/${row.location_id}/`);
}, },
}, },
{
field: 'po'
},
{ {
field: 'buttons', field: 'buttons',
title: '{% trans "Actions" %}', title: '{% trans "Actions" %}',
@ -161,7 +164,10 @@ function showFulfilledSubTable(index, row, element) {
return renderLink(text, `/stock/item/${row.pk}/`); return renderLink(text, `/stock/item/${row.pk}/`);
}, },
} },
{
field: 'po'
},
], ],
}); });
} }
@ -271,6 +277,25 @@ $("#so-lines-table").inventreeTable({
field: 'notes', field: 'notes',
title: '{% trans "Notes" %}', title: '{% trans "Notes" %}',
}, },
{
field: 'po',
title: '{% trans "PO" %}',
formatter: function(value, row, index, field) {
var po_name = "";
if (row.allocated) {
row.allocations.forEach(function(allocation) {
if (allocation.po != po_name) {
if (po_name) {
po_name = "-";
} else {
po_name = allocation.po
}
}
})
}
return `<div>` + po_name + `</div>`;
}
},
{% if order.status == SalesOrderStatus.PENDING %} {% if order.status == SalesOrderStatus.PENDING %}
{ {
field: 'buttons', field: 'buttons',

View File

@ -90,7 +90,7 @@ class SalesOrderDetail(InvenTreeRoleMixin, DetailView):
""" Detail view for a SalesOrder object """ """ Detail view for a SalesOrder object """
context_object_name = 'order' context_object_name = 'order'
queryset = SalesOrder.objects.all().prefetch_related('lines') queryset = SalesOrder.objects.all().prefetch_related('lines__allocations__item__purchase_order')
template_name = 'order/sales_order_detail.html' template_name = 'order/sales_order_detail.html'

View File

@ -1,8 +1,14 @@
# -*- coding: utf-8 -*-
""" This module provides template tags for extra functionality """ This module provides template tags for extra functionality
over and above the built-in Django tags. over and above the built-in Django tags.
""" """
import os import os
from django.utils.translation import ugettext_lazy as _
from django.conf import settings as djangosettings
from django import template from django import template
from django.urls import reverse from django.urls import reverse
from django.utils.safestring import mark_safe from django.utils.safestring import mark_safe
@ -68,6 +74,33 @@ def part_allocation_count(build, part, *args, **kwargs):
return InvenTree.helpers.decimal2string(build.getAllocatedQuantity(part)) return InvenTree.helpers.decimal2string(build.getAllocatedQuantity(part))
@register.simple_tag()
def inventree_in_debug_mode(*args, **kwargs):
""" Return True if the server is running in DEBUG mode """
return djangosettings.DEBUG
@register.simple_tag()
def inventree_docker_mode(*args, **kwargs):
""" Return True if the server is running as a Docker image """
return djangosettings.DOCKER
@register.simple_tag()
def inventree_db_engine(*args, **kwargs):
""" Return the InvenTree database backend e.g. 'postgresql' """
db = djangosettings.DATABASES['default']
engine = db.get('ENGINE', _('Unknown database'))
engine = engine.replace('django.db.backends.', '')
return engine
@register.simple_tag() @register.simple_tag()
def inventree_instance_name(*args, **kwargs): def inventree_instance_name(*args, **kwargs):
""" Return the InstanceName associated with the current database """ """ Return the InstanceName associated with the current database """

View File

@ -1370,6 +1370,12 @@ class StockItem(MPTTModel):
if self.location: if self.location:
s += ' @ {loc}'.format(loc=self.location.name) s += ' @ {loc}'.format(loc=self.location.name)
if self.purchase_order:
s += " ({pre}{po})".format(
pre=helpers.getSetting("PURCHASEORDER_REFERENCE_PREFIX"),
po=self.purchase_order,
)
return s return s
@transaction.atomic @transaction.atomic

View File

@ -89,6 +89,15 @@ function setFieldOptions(fieldName, optionList, options={}) {
} }
function clearFieldOptions(fieldName) {
/**
* Clear (emtpy) the options list for a particular field
*/
setFieldOptions(fieldName, []);
}
function reloadFieldOptions(fieldName, options) { function reloadFieldOptions(fieldName, options) {
/* Reload the options for a given field, /* Reload the options for a given field,
* using an AJAX request. * using an AJAX request.

View File

@ -1218,6 +1218,17 @@ function createNewStockItem(options) {
field: 'part', field: 'part',
action: function(value) { action: function(value) {
if (!value) {
// No part chosen
clearFieldOptions('supplier_part');
enableField('serial_numbers', false);
enableField('purchase_price_0', false);
enableField('purchase_price_1', false);
return;
}
// Reload options for supplier part // Reload options for supplier part
reloadFieldOptions( reloadFieldOptions(
'supplier_part', 'supplier_part',
@ -1243,6 +1254,9 @@ function createNewStockItem(options) {
enableField('serial_numbers', response.trackable); enableField('serial_numbers', response.trackable);
clearField('serial_numbers'); clearField('serial_numbers');
enableField('purchase_price_0', response.purchaseable);
enableField('purchase_price_1', response.purchaseable);
// Populate the expiry date // Populate the expiry date
if (response.default_expiry <= 0) { if (response.default_expiry <= 0) {
// No expiry date // No expiry date

View File

@ -13,6 +13,27 @@
<td>{% trans "Instance Name" %}</td> <td>{% trans "Instance Name" %}</td>
<td>{% inventree_instance_name %}</td> <td>{% inventree_instance_name %}</td>
</tr> </tr>
<tr>
<td><span class='fas fa-database'></span></td>
<td>{% trans "Database" %}</td>
<td>{% inventree_db_engine %}</td>
</tr>
{% inventree_in_debug_mode as debug_mode %}
{% if debug_mode %}
<tr>
<td><span class='fas fa-laptop-code'></span></td>
<td>{% trans "Debug Mode" %}</td>
<td>{% trans "Server is running in debug mode" %}</td>
</tr>
{% endif %}
{% inventree_docker_mode as docker_mode %}
{% if docker_mode %}
<tr>
<td><span class='fab fa-docker'></span></td>
<td>{% trans "Docker Mode" %}</td>
<td>{% trans "Server is deployed using docker" %}</td>
</tr>
{% endif %}
{% if user.is_staff %} {% if user.is_staff %}
<tr> <tr>
<td><span class='fas fa-server'></span></td> <td><span class='fas fa-server'></span></td>

View File

@ -3,3 +3,6 @@ InvenTree-Version: {% inventree_version %}
Django Version: {% django_version %} Django Version: {% django_version %}
{% inventree_commit_hash as hash %}{% if hash %}Commit Hash: {{ hash }}{% endif %} {% inventree_commit_hash as hash %}{% if hash %}Commit Hash: {{ hash }}{% endif %}
{% inventree_commit_date as commit_date %}{% if commit_date %}Commit Date: {{ commit_date }}{% endif %} {% inventree_commit_date as commit_date %}{% if commit_date %}Commit Date: {{ commit_date }}{% endif %}
Database: {% inventree_db_engine %}
Debug-Mode: {% inventree_in_debug_mode %}
Deployed using Docker: {% inventree_docker_mode %}

View File

@ -14,6 +14,7 @@ ENV INVENTREE_REPO="${repository}"
ENV INVENTREE_BRANCH="${branch}" ENV INVENTREE_BRANCH="${branch}"
ENV INVENTREE_LOG_LEVEL="INFO" ENV INVENTREE_LOG_LEVEL="INFO"
ENV INVENTREE_DOCKER="true"
# InvenTree paths # InvenTree paths
ENV INVENTREE_SRC_DIR="${INVENTREE_HOME}/src" ENV INVENTREE_SRC_DIR="${INVENTREE_HOME}/src"