mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
Merge pull request #1000 from SchrodingersGat/installed-in
Installed in
This commit is contained in:
commit
41d6ad2db9
@ -157,6 +157,11 @@ $.fn.inventreeTable = function(options) {
|
||||
console.log('Could not get list of visible columns!');
|
||||
}
|
||||
}
|
||||
|
||||
// Optionally, link buttons to the table selection
|
||||
if (options.buttons) {
|
||||
linkButtonsToSelection(table, options.buttons);
|
||||
}
|
||||
}
|
||||
|
||||
function customGroupSorter(sortName, sortOrder, sortData) {
|
||||
|
@ -19,7 +19,7 @@
|
||||
loadStockTable($("#stock-table"), {
|
||||
params: {
|
||||
location_detail: true,
|
||||
part_details: true,
|
||||
part_detail: true,
|
||||
build: {{ build.id }},
|
||||
},
|
||||
groupByField: 'location',
|
||||
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1273,7 +1273,7 @@ class POLineItemEdit(AjaxUpdateView):
|
||||
form = super().get_form()
|
||||
|
||||
# Prevent user from editing order once line item is assigned
|
||||
form.fields.pop('order')
|
||||
form.fields['order'].widget = HiddenInput()
|
||||
|
||||
return form
|
||||
|
||||
|
@ -476,6 +476,26 @@ class StockList(generics.ListCreateAPIView):
|
||||
if sales_order:
|
||||
queryset = queryset.filter(sales_order=sales_order)
|
||||
|
||||
# Filter stock items which are installed in another (specific) stock item
|
||||
installed_in = params.get('installed_in', None)
|
||||
|
||||
if installed_in:
|
||||
# Note: The "installed_in" field is called "belongs_to"
|
||||
queryset = queryset.filter(belongs_to=installed_in)
|
||||
|
||||
# Filter stock items which are installed in another stock item
|
||||
installed = params.get('installed', None)
|
||||
|
||||
if installed is not None:
|
||||
installed = str2bool(installed)
|
||||
|
||||
if installed:
|
||||
# Exclude items which are *not* installed in another item
|
||||
queryset = queryset.exclude(belongs_to=None)
|
||||
else:
|
||||
# Exclude items which are instaled in another item
|
||||
queryset = queryset.filter(belongs_to=None)
|
||||
|
||||
# Filter by customer
|
||||
customer = params.get('customer', None)
|
||||
|
||||
|
@ -271,6 +271,28 @@ class ExportOptionsForm(HelperForm):
|
||||
self.fields['file_format'].choices = self.get_format_choices()
|
||||
|
||||
|
||||
class UninstallStockForm(forms.ModelForm):
|
||||
"""
|
||||
Form for uninstalling a stock item which is installed in another item.
|
||||
"""
|
||||
|
||||
location = TreeNodeChoiceField(queryset=StockLocation.objects.all(), label=_('Location'), help_text=_('Destination location for uninstalled items'))
|
||||
|
||||
note = forms.CharField(label=_('Notes'), required=False, help_text=_('Add transaction note (optional)'))
|
||||
|
||||
confirm = forms.BooleanField(required=False, initial=False, label=_('Confirm uninstall'), help_text=_('Confirm removal of installed stock items'))
|
||||
|
||||
class Meta:
|
||||
|
||||
model = StockItem
|
||||
|
||||
fields = [
|
||||
'location',
|
||||
'note',
|
||||
'confirm',
|
||||
]
|
||||
|
||||
|
||||
class AdjustStockForm(forms.ModelForm):
|
||||
""" Form for performing simple stock adjustments.
|
||||
|
||||
@ -282,15 +304,15 @@ class AdjustStockForm(forms.ModelForm):
|
||||
This form is used for managing stock adjuments for single or multiple stock items.
|
||||
"""
|
||||
|
||||
destination = TreeNodeChoiceField(queryset=StockLocation.objects.all(), label='Destination', required=True, help_text=_('Destination stock location'))
|
||||
destination = TreeNodeChoiceField(queryset=StockLocation.objects.all(), label=_('Destination'), required=True, help_text=_('Destination stock location'))
|
||||
|
||||
note = forms.CharField(label='Notes', required=True, help_text='Add note (required)')
|
||||
note = forms.CharField(label=_('Notes'), required=True, help_text=_('Add note (required)'))
|
||||
|
||||
# transaction = forms.BooleanField(required=False, initial=False, label='Create Transaction', help_text='Create a stock transaction for these parts')
|
||||
|
||||
confirm = forms.BooleanField(required=False, initial=False, label='Confirm stock adjustment', help_text=_('Confirm movement of stock items'))
|
||||
confirm = forms.BooleanField(required=False, initial=False, label=_('Confirm stock adjustment'), help_text=_('Confirm movement of stock items'))
|
||||
|
||||
set_loc = forms.BooleanField(required=False, initial=False, label='Set Default Location', help_text=_('Set the destination as the default location for selected parts'))
|
||||
set_loc = forms.BooleanField(required=False, initial=False, label=_('Set Default Location'), help_text=_('Set the destination as the default location for selected parts'))
|
||||
|
||||
class Meta:
|
||||
model = StockItem
|
||||
|
19
InvenTree/stock/migrations/0051_auto_20200928_0928.py
Normal file
19
InvenTree/stock/migrations/0051_auto_20200928_0928.py
Normal file
@ -0,0 +1,19 @@
|
||||
# Generated by Django 3.0.7 on 2020-09-28 09:28
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('stock', '0050_auto_20200821_1403'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='stockitem',
|
||||
name='belongs_to',
|
||||
field=models.ForeignKey(blank=True, help_text='Is this item installed in another item?', null=True, on_delete=django.db.models.deletion.DO_NOTHING, related_name='installed_parts', to='stock.StockItem', verbose_name='Installed In'),
|
||||
),
|
||||
]
|
@ -341,7 +341,7 @@ class StockItem(MPTTModel):
|
||||
'self',
|
||||
verbose_name=_('Installed In'),
|
||||
on_delete=models.DO_NOTHING,
|
||||
related_name='owned_parts', blank=True, null=True,
|
||||
related_name='installed_parts', blank=True, null=True,
|
||||
help_text=_('Is this item installed in another item?')
|
||||
)
|
||||
|
||||
@ -585,6 +585,78 @@ class StockItem(MPTTModel):
|
||||
|
||||
return True
|
||||
|
||||
def installedItemCount(self):
|
||||
"""
|
||||
Return the number of stock items installed inside this one.
|
||||
"""
|
||||
|
||||
return self.installed_parts.count()
|
||||
|
||||
def hasInstalledItems(self):
|
||||
"""
|
||||
Returns true if this stock item has other stock items installed in it.
|
||||
"""
|
||||
|
||||
return self.installedItemCount() > 0
|
||||
|
||||
@transaction.atomic
|
||||
def installIntoStockItem(self, otherItem, user, notes):
|
||||
"""
|
||||
Install this stock item into another stock item.
|
||||
|
||||
Args
|
||||
otherItem: The stock item to install this item into
|
||||
user: The user performing the operation
|
||||
notes: Any notes associated with the operation
|
||||
"""
|
||||
|
||||
# Cannot be already installed in another stock item!
|
||||
if self.belongs_to is not None:
|
||||
return False
|
||||
|
||||
# TODO - Are there any other checks that need to be performed at this stage?
|
||||
|
||||
# Mark this stock item as belonging to the other one
|
||||
self.belongs_to = otherItem
|
||||
|
||||
self.save()
|
||||
|
||||
# Add a transaction note!
|
||||
self.addTransactionNote(
|
||||
_('Installed in stock item') + ' ' + str(otherItem.pk),
|
||||
user,
|
||||
notes=notes
|
||||
)
|
||||
|
||||
@transaction.atomic
|
||||
def uninstallIntoLocation(self, location, user, notes):
|
||||
"""
|
||||
Uninstall this stock item from another item, into a location.
|
||||
|
||||
Args:
|
||||
location: The stock location where the item will be moved
|
||||
user: The user performing the operation
|
||||
notes: Any notes associated with the operation
|
||||
"""
|
||||
|
||||
# If the stock item is not installed in anything, ignore
|
||||
if self.belongs_to is None:
|
||||
return False
|
||||
|
||||
# TODO - Are there any other checks that need to be performed at this stage?
|
||||
|
||||
self.belongs_to = None
|
||||
self.location = location
|
||||
|
||||
self.save()
|
||||
|
||||
# Add a transaction note!
|
||||
self.addTransactionNote(
|
||||
_('Uninstalled into location') + ' ' + str(location),
|
||||
user,
|
||||
notes=notes
|
||||
)
|
||||
|
||||
@property
|
||||
def children(self):
|
||||
""" Return a list of the child items which have been split from this stock item """
|
||||
|
@ -31,6 +31,7 @@ loadStockTable($("#stock-table"), {
|
||||
part_details: true,
|
||||
ancestor: {{ item.id }},
|
||||
},
|
||||
name: 'item-childs',
|
||||
groupByField: 'location',
|
||||
buttons: [
|
||||
'#stock-options',
|
||||
|
184
InvenTree/stock/templates/stock/item_installed.html
Normal file
184
InvenTree/stock/templates/stock/item_installed.html
Normal file
@ -0,0 +1,184 @@
|
||||
{% extends "stock/item_base.html" %}
|
||||
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block details %}
|
||||
|
||||
{% include "stock/tabs.html" with tab='installed' %}
|
||||
|
||||
<h4>{% trans "Installed Stock Items" %}</h4>
|
||||
<hr>
|
||||
|
||||
<div id='button-toolbar'>
|
||||
<div class='button-toolbar container-fluid' style='float: right;'>
|
||||
<div class="btn-group">
|
||||
<button id='stock-options' class="btn btn-primary dropdown-toggle" type="button" data-toggle="dropdown">{% trans "Options" %}<span class="caret"></span></button>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="#" id='multi-item-uninstall' title='{% trans "Uninstall selected stock items" %}'>{% trans "Uninstall" %}</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<table class='table table-striped table-condensed' id='installed-table' data-toolbar='#button-toolbar'>
|
||||
</table>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block js_ready %}
|
||||
|
||||
{{ block.super }}
|
||||
|
||||
$('#installed-table').inventreeTable({
|
||||
formatNoMatches: function() {
|
||||
return '{% trans "No stock items installed" %}';
|
||||
},
|
||||
url: "{% url 'api-stock-list' %}",
|
||||
queryParams: {
|
||||
installed_in: {{ item.id }},
|
||||
part_detail: true,
|
||||
},
|
||||
name: 'stock-item-installed',
|
||||
url: "{% url 'api-stock-list' %}",
|
||||
showColumns: true,
|
||||
columns: [
|
||||
{
|
||||
checkbox: true,
|
||||
title: '{% trans 'Select' %}',
|
||||
searchable: false,
|
||||
switchable: false,
|
||||
},
|
||||
{
|
||||
field: 'pk',
|
||||
title: 'ID',
|
||||
visible: false,
|
||||
switchable: false,
|
||||
},
|
||||
{
|
||||
field: 'part_name',
|
||||
title: '{% trans "Part" %}',
|
||||
sortable: true,
|
||||
formatter: function(value, row, index, field) {
|
||||
|
||||
var url = `/stock/item/${row.pk}/`;
|
||||
var thumb = row.part_detail.thumbnail;
|
||||
var name = row.part_detail.full_name;
|
||||
|
||||
html = imageHoverIcon(thumb) + renderLink(name, url);
|
||||
|
||||
return html;
|
||||
}
|
||||
},
|
||||
{
|
||||
field: 'IPN',
|
||||
title: 'IPN',
|
||||
sortable: true,
|
||||
formatter: function(value, row, index, field) {
|
||||
return row.part_detail.IPN;
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'part_description',
|
||||
title: '{% trans "Description" %}',
|
||||
sortable: true,
|
||||
formatter: function(value, row, index, field) {
|
||||
return row.part_detail.description;
|
||||
}
|
||||
},
|
||||
{
|
||||
field: 'quantity',
|
||||
title: '{% trans "Stock" %}',
|
||||
sortable: true,
|
||||
formatter: function(value, row, index, field) {
|
||||
|
||||
var val = parseFloat(value);
|
||||
|
||||
// If there is a single unit with a serial number, use the serial number
|
||||
if (row.serial && row.quantity == 1) {
|
||||
val = '# ' + row.serial;
|
||||
} else {
|
||||
val = +val.toFixed(5);
|
||||
}
|
||||
|
||||
var html = renderLink(val, `/stock/item/${row.pk}/`);
|
||||
|
||||
return html;
|
||||
}
|
||||
},
|
||||
{
|
||||
field: 'status',
|
||||
title: '{% trans "Status" %}',
|
||||
sortable: 'true',
|
||||
formatter: function(value, row, index, field) {
|
||||
return stockStatusDisplay(value);
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'batch',
|
||||
title: '{% trans "Batch" %}',
|
||||
sortable: true,
|
||||
},
|
||||
{
|
||||
field: 'actions',
|
||||
switchable: false,
|
||||
title: '',
|
||||
formatter: function(value, row) {
|
||||
var pk = row.pk;
|
||||
|
||||
var html = `<div class='btn-group float-right' role='group'>`;
|
||||
|
||||
html += makeIconButton('fa-trash-alt icon-red', 'button-uninstall', pk, '{% trans "Uninstall item" %}');
|
||||
|
||||
html += `</div>`;
|
||||
|
||||
return html;
|
||||
}
|
||||
}
|
||||
],
|
||||
onLoadSuccess: function() {
|
||||
|
||||
var table = $('#installed-table');
|
||||
|
||||
// Find buttons and associate actions
|
||||
table.find('.button-uninstall').click(function() {
|
||||
var pk = $(this).attr('pk');
|
||||
|
||||
launchModalForm(
|
||||
"{% url 'stock-item-uninstall' %}",
|
||||
{
|
||||
data: {
|
||||
'items[]': [pk],
|
||||
},
|
||||
reload: true,
|
||||
}
|
||||
);
|
||||
});
|
||||
},
|
||||
buttons: [
|
||||
'#stock-options',
|
||||
]
|
||||
});
|
||||
|
||||
$('#multi-item-uninstall').click(function() {
|
||||
|
||||
var selections = $('#installed-table').bootstrapTable('getSelections');
|
||||
|
||||
var items = [];
|
||||
|
||||
selections.forEach(function(item) {
|
||||
items.push(item.pk);
|
||||
});
|
||||
|
||||
launchModalForm(
|
||||
"{% url 'stock-item-uninstall' %}",
|
||||
{
|
||||
data: {
|
||||
'items[]': items,
|
||||
},
|
||||
reload: true,
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
{% endblock %}
|
28
InvenTree/stock/templates/stock/stock_uninstall.html
Normal file
28
InvenTree/stock/templates/stock/stock_uninstall.html
Normal file
@ -0,0 +1,28 @@
|
||||
{% extends "modal_form.html" %}
|
||||
{% load i18n %}
|
||||
{% load inventree_extras %}
|
||||
|
||||
{% block pre_form_content %}
|
||||
|
||||
<div class='alert alert-block alert-success'>
|
||||
{% trans "The following stock items will be uninstalled" %}
|
||||
</div>
|
||||
|
||||
<ul class='list-group'>
|
||||
{% for item in stock_items %}
|
||||
<li class='list-group-item'>
|
||||
{% include "hover_image.html" with image=item.part.image hover=False %}
|
||||
{{ item }}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block form_data %}
|
||||
|
||||
{% for item in stock_items %}
|
||||
<input type='hidden' name='stock-item-{{ item.pk }}' value='{{ item.pk }}'/>
|
||||
{% endfor %}
|
||||
|
||||
{% endblock %}
|
@ -38,4 +38,12 @@
|
||||
<a href="{% url 'stock-item-children' item.id %}">{% trans "Children" %}{% if item.child_count > 0 %}<span class='badge'>{{ item.child_count }}</span>{% endif %}</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
{% if item.part.assembly or item.installedItemCount > 0 %}
|
||||
<li {% if tab == 'installed' %} class='active'{% endif %}>
|
||||
<a href="{% url 'stock-item-installed' item.id %}">
|
||||
{% trans "Installed Items" %}
|
||||
{% if item.installedItemCount > 0 %}<span class='badge'>{{ item.installedItemCount }}</span>{% endif %}
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
@ -34,6 +34,7 @@ stock_item_detail_urls = [
|
||||
url(r'^test/', views.StockItemDetail.as_view(template_name='stock/item_tests.html'), name='stock-item-test-results'),
|
||||
url(r'^children/', views.StockItemDetail.as_view(template_name='stock/item_childs.html'), name='stock-item-children'),
|
||||
url(r'^attachments/', views.StockItemDetail.as_view(template_name='stock/item_attachments.html'), name='stock-item-attachments'),
|
||||
url(r'^installed/', views.StockItemDetail.as_view(template_name='stock/item_installed.html'), name='stock-item-installed'),
|
||||
url(r'^notes/', views.StockItemNotes.as_view(), name='stock-item-notes'),
|
||||
|
||||
url('^.*$', views.StockItemDetail.as_view(), name='stock-item-detail'),
|
||||
@ -59,6 +60,8 @@ stock_urls = [
|
||||
|
||||
url(r'^item/new/?', views.StockItemCreate.as_view(), name='stock-item-create'),
|
||||
|
||||
url(r'^item/uninstall/', views.StockItemUninstall.as_view(), name='stock-item-uninstall'),
|
||||
|
||||
url(r'^item/test-report-download/', views.StockItemTestReportDownload.as_view(), name='stock-item-test-report-download'),
|
||||
url(r'^item/print-stock-labels/', views.StockItemPrintLabels.as_view(), name='stock-item-print-labels'),
|
||||
|
||||
|
@ -683,6 +683,139 @@ class StockItemQRCode(QRCodeView):
|
||||
return None
|
||||
|
||||
|
||||
class StockItemUninstall(AjaxView, FormMixin):
|
||||
"""
|
||||
View for uninstalling one or more StockItems,
|
||||
which are installed in another stock item.
|
||||
|
||||
Stock items are uninstalled into a location,
|
||||
defaulting to the location that they were "in" before they were installed.
|
||||
|
||||
If multiple default locations are detected,
|
||||
leave the final location up to the user.
|
||||
"""
|
||||
|
||||
ajax_template_name = 'stock/stock_uninstall.html'
|
||||
ajax_form_title = _('Uninstall Stock Items')
|
||||
form_class = StockForms.UninstallStockForm
|
||||
|
||||
# List of stock items to uninstall (initially empty)
|
||||
stock_items = []
|
||||
|
||||
def get_stock_items(self):
|
||||
|
||||
return self.stock_items
|
||||
|
||||
def get_initial(self):
|
||||
|
||||
initials = super().get_initial().copy()
|
||||
|
||||
# Keep track of the current locations of stock items
|
||||
current_locations = set()
|
||||
|
||||
# Keep track of the default locations for stock items
|
||||
default_locations = set()
|
||||
|
||||
for item in self.stock_items:
|
||||
|
||||
if item.location:
|
||||
current_locations.add(item.location)
|
||||
|
||||
if item.part.default_location:
|
||||
default_locations.add(item.part.default_location)
|
||||
|
||||
if len(current_locations) == 1:
|
||||
# If the selected stock items are currently in a single location,
|
||||
# select that location as the destination.
|
||||
initials['location'] = next(iter(current_locations))
|
||||
elif len(current_locations) == 0:
|
||||
# There are no current locations set
|
||||
if len(default_locations) == 1:
|
||||
# Select the single default location
|
||||
initials['location'] = next(iter(default_locations))
|
||||
|
||||
return initials
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
|
||||
""" Extract list of stock items, which are supplied as a list,
|
||||
e.g. items[]=1,2,3
|
||||
"""
|
||||
|
||||
if 'items[]' in request.GET:
|
||||
self.stock_items = StockItem.objects.filter(id__in=request.GET.getlist('items[]'))
|
||||
else:
|
||||
self.stock_items = []
|
||||
|
||||
return self.renderJsonResponse(request, self.get_form())
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
|
||||
"""
|
||||
Extract a list of stock items which are included as hidden inputs in the form data.
|
||||
"""
|
||||
|
||||
items = []
|
||||
|
||||
for item in self.request.POST:
|
||||
if item.startswith('stock-item-'):
|
||||
pk = item.replace('stock-item-', '')
|
||||
|
||||
try:
|
||||
stock_item = StockItem.objects.get(pk=pk)
|
||||
items.append(stock_item)
|
||||
except (ValueError, StockItem.DoesNotExist):
|
||||
pass
|
||||
|
||||
self.stock_items = items
|
||||
|
||||
# Assume the form is valid, until it isn't!
|
||||
valid = True
|
||||
|
||||
confirmed = str2bool(request.POST.get('confirm'))
|
||||
|
||||
note = request.POST.get('note', '')
|
||||
|
||||
location = request.POST.get('location', None)
|
||||
|
||||
if location:
|
||||
try:
|
||||
location = StockLocation.objects.get(pk=location)
|
||||
except (ValueError, StockLocation.DoesNotExist):
|
||||
location = None
|
||||
|
||||
if not location:
|
||||
# Location is required!
|
||||
valid = False
|
||||
|
||||
form = self.get_form()
|
||||
|
||||
if not confirmed:
|
||||
valid = False
|
||||
form.errors['confirm'] = [_('Confirm stock adjustment')]
|
||||
|
||||
data = {
|
||||
'form_valid': valid,
|
||||
}
|
||||
|
||||
if valid:
|
||||
# Ok, now let's actually uninstall the stock items
|
||||
for item in self.stock_items:
|
||||
item.uninstallIntoLocation(location, request.user, note)
|
||||
|
||||
data['success'] = _('Uninstalled stock items')
|
||||
|
||||
return self.renderJsonResponse(request, form=form, data=data)
|
||||
|
||||
def get_context_data(self):
|
||||
|
||||
context = super().get_context_data()
|
||||
|
||||
context['stock_items'] = self.get_stock_items()
|
||||
|
||||
return context
|
||||
|
||||
|
||||
class StockAdjust(AjaxView, FormMixin):
|
||||
""" View for enacting simple stock adjustments:
|
||||
|
||||
@ -1037,8 +1170,9 @@ class StockItemEdit(AjaxUpdateView):
|
||||
query = query.filter(part=item.part.id)
|
||||
form.fields['supplier_part'].queryset = query
|
||||
|
||||
if not item.part.trackable or not item.serialized:
|
||||
form.fields.pop('serial')
|
||||
# Hide the serial number field if it is not required
|
||||
if not item.part.trackable and not item.serialized:
|
||||
form.fields['serial'].widget = HiddenInput()
|
||||
|
||||
return form
|
||||
|
||||
|
@ -238,7 +238,7 @@ function loadStockTable(table, options) {
|
||||
|
||||
var filters = {};
|
||||
|
||||
var filterKey = options.filterKey || "stock";
|
||||
var filterKey = options.filterKey || options.name || "stock";
|
||||
|
||||
if (!options.disableFilters) {
|
||||
filters = loadTableFilters(filterKey);
|
||||
@ -416,14 +416,6 @@ function loadStockTable(table, options) {
|
||||
visible: false,
|
||||
switchable: false,
|
||||
},
|
||||
{
|
||||
field: 'IPN',
|
||||
title: 'IPN',
|
||||
sortable: true,
|
||||
formatter: function(value, row, index, field) {
|
||||
return row.part_detail.IPN;
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'part_name',
|
||||
title: '{% trans "Part" %}',
|
||||
@ -439,6 +431,14 @@ function loadStockTable(table, options) {
|
||||
return html;
|
||||
}
|
||||
},
|
||||
{
|
||||
field: 'IPN',
|
||||
title: 'IPN',
|
||||
sortable: true,
|
||||
formatter: function(value, row, index, field) {
|
||||
return row.part_detail.IPN;
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'part_description',
|
||||
title: '{% trans "Description" %}',
|
||||
@ -512,18 +512,22 @@ function loadStockTable(table, options) {
|
||||
title: '{% trans "Location" %}',
|
||||
sortable: true,
|
||||
formatter: function(value, row, index, field) {
|
||||
if (value) {
|
||||
if (row.belongs_to) {
|
||||
var text = "{% trans 'Installed in Stock Item ' %}" + row.belongs_to;
|
||||
var url = `/stock/item/${row.belongs_to}/installed/`;
|
||||
|
||||
return renderLink(text, url);
|
||||
} else if (row.customer) {
|
||||
var text = "{% trans "Shipped to customer" %}";
|
||||
return renderLink(text, `/company/${row.customer}/assigned-stock/`);
|
||||
}
|
||||
else if (value) {
|
||||
return renderLink(value, `/stock/location/${row.location}/`);
|
||||
}
|
||||
else {
|
||||
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>';
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
field: 'notes',
|
||||
|
@ -65,6 +65,11 @@ function getAvailableTableFilters(tableKey) {
|
||||
title: '{% trans "In Stock" %}',
|
||||
description: '{% trans "Show items which are in stock" %}',
|
||||
},
|
||||
installed: {
|
||||
type: 'bool',
|
||||
title: '{% trans "Installed" %}',
|
||||
description: '{% trans "Show stock items which are installed in another item" %}',
|
||||
},
|
||||
sent_to_customer: {
|
||||
type: 'bool',
|
||||
title: '{% trans "Sent to customer" %}',
|
||||
|
Loading…
Reference in New Issue
Block a user