mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
Merge branch 'negative-stock-fix'
This commit is contained in:
commit
5f2ca784c9
@ -14,7 +14,7 @@
|
|||||||
|
|
||||||
function defaultFilters() {
|
function defaultFilters() {
|
||||||
return {
|
return {
|
||||||
stock: "cascade=1",
|
stock: "cascade=1&in_stock=1",
|
||||||
build: "",
|
build: "",
|
||||||
parts: "cascade=1",
|
parts: "cascade=1",
|
||||||
company: "",
|
company: "",
|
||||||
|
55
InvenTree/company/migrations/0022_auto_20200613_1045.py
Normal file
55
InvenTree/company/migrations/0022_auto_20200613_1045.py
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
# Generated by Django 3.0.7 on 2020-06-13 10:45
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import django.db.models.deletion
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('part', '0045_auto_20200605_0932'),
|
||||||
|
('company', '0021_remove_supplierpart_manufacturer_name'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='company',
|
||||||
|
name='address',
|
||||||
|
field=models.CharField(blank=True, help_text='Company address', max_length=200, verbose_name='Address'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='company',
|
||||||
|
name='contact',
|
||||||
|
field=models.CharField(blank=True, help_text='Point of contact', max_length=100, verbose_name='Contact'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='company',
|
||||||
|
name='description',
|
||||||
|
field=models.CharField(help_text='Description of the company', max_length=500, verbose_name='Company description'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='company',
|
||||||
|
name='email',
|
||||||
|
field=models.EmailField(blank=True, help_text='Contact email address', max_length=254, verbose_name='Email'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='company',
|
||||||
|
name='name',
|
||||||
|
field=models.CharField(help_text='Company name', max_length=100, unique=True, verbose_name='Company name'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='company',
|
||||||
|
name='phone',
|
||||||
|
field=models.CharField(blank=True, help_text='Contact phone number', max_length=50, verbose_name='Phone number'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='company',
|
||||||
|
name='website',
|
||||||
|
field=models.URLField(blank=True, help_text='Company website URL', verbose_name='Website'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='supplierpart',
|
||||||
|
name='part',
|
||||||
|
field=models.ForeignKey(help_text='Select part', limit_choices_to={'is_template': False, 'purchaseable': True}, on_delete=django.db.models.deletion.CASCADE, related_name='supplier_parts', to='part.Part', verbose_name='Base Part'),
|
||||||
|
),
|
||||||
|
]
|
@ -80,21 +80,25 @@ class Company(models.Model):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
name = models.CharField(max_length=100, blank=False, unique=True,
|
name = models.CharField(max_length=100, blank=False, unique=True,
|
||||||
help_text=_('Company name'))
|
help_text=_('Company name'),
|
||||||
|
verbose_name=_('Company name'))
|
||||||
|
|
||||||
description = models.CharField(max_length=500, help_text=_('Description of the company'))
|
description = models.CharField(max_length=500, verbose_name=_('Company description'), help_text=_('Description of the company'))
|
||||||
|
|
||||||
website = models.URLField(blank=True, help_text=_('Company website URL'))
|
website = models.URLField(blank=True, verbose_name=_('Website'), help_text=_('Company website URL'))
|
||||||
|
|
||||||
address = models.CharField(max_length=200,
|
address = models.CharField(max_length=200,
|
||||||
|
verbose_name=_('Address'),
|
||||||
blank=True, help_text=_('Company address'))
|
blank=True, help_text=_('Company address'))
|
||||||
|
|
||||||
phone = models.CharField(max_length=50,
|
phone = models.CharField(max_length=50,
|
||||||
|
verbose_name=_('Phone number'),
|
||||||
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, verbose_name=_('Email'), help_text=_('Contact email address'))
|
||||||
|
|
||||||
contact = models.CharField(max_length=100,
|
contact = models.CharField(max_length=100,
|
||||||
|
verbose_name=_('Contact'),
|
||||||
blank=True, help_text=_('Point of contact'))
|
blank=True, help_text=_('Point of contact'))
|
||||||
|
|
||||||
link = InvenTreeURLField(blank=True, help_text=_('Link to external company information'))
|
link = InvenTreeURLField(blank=True, help_text=_('Link to external company information'))
|
||||||
@ -269,6 +273,7 @@ class SupplierPart(models.Model):
|
|||||||
|
|
||||||
part = models.ForeignKey('part.Part', on_delete=models.CASCADE,
|
part = models.ForeignKey('part.Part', on_delete=models.CASCADE,
|
||||||
related_name='supplier_parts',
|
related_name='supplier_parts',
|
||||||
|
verbose_name=_('Base Part'),
|
||||||
limit_choices_to={
|
limit_choices_to={
|
||||||
'purchaseable': True,
|
'purchaseable': True,
|
||||||
'is_template': False,
|
'is_template': False,
|
||||||
|
@ -594,7 +594,16 @@ class Part(MPTTModel):
|
|||||||
def quantity_to_order(self):
|
def quantity_to_order(self):
|
||||||
""" Return the quantity needing to be ordered for this part. """
|
""" Return the quantity needing to be ordered for this part. """
|
||||||
|
|
||||||
required = -1 * self.net_stock
|
# How many do we need to have "on hand" at any point?
|
||||||
|
required = self.net_stock - self.minimum_stock
|
||||||
|
|
||||||
|
if required < 0:
|
||||||
|
return abs(required)
|
||||||
|
|
||||||
|
# Do not need to order any
|
||||||
|
return 0
|
||||||
|
|
||||||
|
required = self.net_stock
|
||||||
return max(required, 0)
|
return max(required, 0)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -191,7 +191,7 @@
|
|||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><b>{% trans "Active" %}</b></td>
|
<td><b>{% trans "Active" %}</b></td>
|
||||||
<td>{% include "slide.html" with state=part.active field='active' %}</td>
|
<td>{% include "slide.html" with state=part.active field='active' disabled=False %}</td>
|
||||||
{% if part.active %}
|
{% if part.active %}
|
||||||
<td>{% trans "Part is active" %}</td>
|
<td>{% trans "Part is active" %}</td>
|
||||||
{% else %}
|
{% else %}
|
||||||
|
@ -40,7 +40,6 @@
|
|||||||
part: {{ part.id }},
|
part: {{ part.id }},
|
||||||
location_detail: true,
|
location_detail: true,
|
||||||
part_detail: true,
|
part_detail: true,
|
||||||
in_stock: true,
|
|
||||||
},
|
},
|
||||||
groupByField: 'location',
|
groupByField: 'location',
|
||||||
buttons: [
|
buttons: [
|
||||||
|
@ -51,15 +51,6 @@
|
|||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if part.trackable %}
|
{% if part.trackable %}
|
||||||
{% if 0 %}
|
|
||||||
<!-- TODO - Add the 'tracking' tab back in -->
|
|
||||||
<li{% ifequal tab 'track' %} class="active"{% endifequal %}>
|
|
||||||
<a href="{% url 'part-track' part.id %}">{% trans "Tracking" %}
|
|
||||||
{% if parts.serials.all|length > 0 %}
|
|
||||||
<span class="badge">{{ part.serials.all|length }}</span>
|
|
||||||
{% endif %}
|
|
||||||
</a></li>
|
|
||||||
{% endif %}
|
|
||||||
<li{% ifequal tab 'tests' %} class='active'{% endifequal %}>
|
<li{% ifequal tab 'tests' %} class='active'{% endifequal %}>
|
||||||
<a href='{% url "part-test-templates" part.id %}'>{% trans "Tests" %}
|
<a href='{% url "part-test-templates" part.id %}'>{% trans "Tests" %}
|
||||||
{% if part.getTestTemplates.count > 0 %}<span class='badge'>{{ part.getTestTemplates.count }}</span>{% endif %}
|
{% if part.getTestTemplates.count > 0 %}<span class='badge'>{{ part.getTestTemplates.count }}</span>{% endif %}
|
||||||
|
@ -71,6 +71,7 @@ class StockItemSerializer(InvenTreeModelSerializer):
|
|||||||
'belongs_to',
|
'belongs_to',
|
||||||
'build',
|
'build',
|
||||||
'build_order',
|
'build_order',
|
||||||
|
'customer',
|
||||||
'sales_order',
|
'sales_order',
|
||||||
'supplier_part',
|
'supplier_part',
|
||||||
'supplier_part__supplier',
|
'supplier_part__supplier',
|
||||||
@ -141,6 +142,7 @@ class StockItemSerializer(InvenTreeModelSerializer):
|
|||||||
'batch',
|
'batch',
|
||||||
'build_order',
|
'build_order',
|
||||||
'belongs_to',
|
'belongs_to',
|
||||||
|
'customer',
|
||||||
'in_stock',
|
'in_stock',
|
||||||
'link',
|
'link',
|
||||||
'location',
|
'location',
|
||||||
|
@ -248,7 +248,6 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
part_detail: true,
|
part_detail: true,
|
||||||
location_detail: true,
|
location_detail: true,
|
||||||
in_stock: true,
|
|
||||||
},
|
},
|
||||||
url: "{% url 'api-stock-list' %}",
|
url: "{% url 'api-stock-list' %}",
|
||||||
});
|
});
|
||||||
|
@ -494,10 +494,15 @@ function loadStockTable(table, options) {
|
|||||||
sortable: true,
|
sortable: true,
|
||||||
formatter: function(value, row, index, field) {
|
formatter: function(value, row, index, field) {
|
||||||
if (value) {
|
if (value) {
|
||||||
return renderLink(value, '/stock/location/' + row.location + '/');
|
return renderLink(value, `/stock/location/${row.location}/`);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return '<i>{% trans "No stock location set" %}</i>';
|
if (row.customer) {
|
||||||
|
var text = "{% trans "Shipped to customer" %}";
|
||||||
|
return renderLink(text, `/company/${row.customer}/assigned-stock/`);
|
||||||
|
} else {
|
||||||
|
return '<i>{% trans "No stock location set" %}</i>';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -14,6 +14,11 @@ function getAvailableTableFilters(tableKey) {
|
|||||||
// Filters for the "Stock" table
|
// Filters for the "Stock" table
|
||||||
if (tableKey == 'stock') {
|
if (tableKey == 'stock') {
|
||||||
return {
|
return {
|
||||||
|
in_stock: {
|
||||||
|
type: 'bool',
|
||||||
|
title: '{% trans "In Stock" %}',
|
||||||
|
description: '{% trans "Show items which are in stock" %}',
|
||||||
|
},
|
||||||
cascade: {
|
cascade: {
|
||||||
type: 'bool',
|
type: 'bool',
|
||||||
title: '{% trans "Include sublocations" %}',
|
title: '{% trans "Include sublocations" %}',
|
||||||
|
Loading…
Reference in New Issue
Block a user