mirror of
https://github.com/inventree/InvenTree.git
synced 2025-05-07 15:58:49 +00:00
Merge remote-tracking branch 'inventree/master'
This commit is contained in:
commit
0498fd633a
@ -1,5 +1,6 @@
|
|||||||
function updateAllocationTotal(id, count, required) {
|
function updateAllocationTotal(id, count, required) {
|
||||||
|
|
||||||
|
count = parseFloat(count);
|
||||||
|
|
||||||
$('#allocation-total-'+id).html(count);
|
$('#allocation-total-'+id).html(count);
|
||||||
|
|
||||||
@ -27,21 +28,24 @@ function loadAllocationTable(table, part_id, part, url, required, button) {
|
|||||||
field: 'stock_item_detail',
|
field: 'stock_item_detail',
|
||||||
title: 'Stock Item',
|
title: 'Stock Item',
|
||||||
formatter: function(value, row, index, field) {
|
formatter: function(value, row, index, field) {
|
||||||
return '' + value.quantity + ' x ' + value.part_name + ' @ ' + value.location_name;
|
return '' + parseFloat(value.quantity) + ' x ' + value.part_name + ' @ ' + value.location_name;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'stock_item_detail.quantity',
|
field: 'stock_item_detail.quantity',
|
||||||
title: 'Available',
|
title: 'Available',
|
||||||
|
formatter: function(value, row, index, field) {
|
||||||
|
return parseFloat(value);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'quantity',
|
field: 'quantity',
|
||||||
title: 'Allocated',
|
title: 'Allocated',
|
||||||
formatter: function(value, row, index, field) {
|
formatter: function(value, row, index, field) {
|
||||||
var html = value;
|
var html = parseFloat(value);
|
||||||
|
|
||||||
var bEdit = "<button class='btn btn-primary item-edit-button btn-sm' type='button' title='Edit stock allocation' url='/build/item/" + row.pk + "/edit/'><span class='glyphicon glyphicon-small glyphicon-edit'></span></button>";
|
var bEdit = "<button class='btn item-edit-button btn-sm' type='button' title='Edit stock allocation' url='/build/item/" + row.pk + "/edit/'><span class='glyphicon glyphicon-small glyphicon-edit'></span></button>";
|
||||||
var bDel = "<button class='btn btn-danger item-del-button btn-sm' type='button' title='Delete stock allocation' url='/build/item/" + row.pk + "/delete/'><span class='glyphicon glyphicon-small glyphicon-trash'></span></button>";
|
var bDel = "<button class='btn item-del-button btn-sm' type='button' title='Delete stock allocation' url='/build/item/" + row.pk + "/delete/'><span class='glyphicon glyphicon-small glyphicon-trash'></span></button>";
|
||||||
|
|
||||||
html += "<div class='btn-group' style='float: right;'>" + bEdit + bDel + "</div>";
|
html += "<div class='btn-group' style='float: right;'>" + bEdit + bDel + "</div>";
|
||||||
|
|
||||||
|
@ -385,6 +385,9 @@ function loadStockTrackingTable(table, options) {
|
|||||||
cols.push({
|
cols.push({
|
||||||
field: 'quantity',
|
field: 'quantity',
|
||||||
title: 'Quantity',
|
title: 'Quantity',
|
||||||
|
formatter: function(value, row, index, field) {
|
||||||
|
return parseFloat(value);
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
cols.push({
|
cols.push({
|
||||||
|
@ -20,6 +20,7 @@ from markdownx.models import MarkdownxField
|
|||||||
|
|
||||||
from InvenTree.status_codes import BuildStatus
|
from InvenTree.status_codes import BuildStatus
|
||||||
from InvenTree.fields import InvenTreeURLField
|
from InvenTree.fields import InvenTreeURLField
|
||||||
|
from InvenTree.helpers import decimal2string
|
||||||
|
|
||||||
from stock.models import StockItem
|
from stock.models import StockItem
|
||||||
from part.models import Part, BomItem
|
from part.models import Part, BomItem
|
||||||
@ -42,7 +43,7 @@ class Build(models.Model):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "Build {q} x {part}".format(q=self.quantity, part=str(self.part))
|
return "Build {q} x {part}".format(q=decimal2string(self.quantity), part=str(self.part))
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
return reverse('build-detail', kwargs={'pk': self.id})
|
return reverse('build-detail', kwargs={'pk': self.id})
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
|
|
||||||
{% block collapse_heading %}
|
{% block collapse_heading %}
|
||||||
<div class='col-sm-2'>
|
<div class='col-sm-2'>
|
||||||
<b>{{ item.sub_part.total_stock }}</b>
|
<b>{% decimal item.sub_part.total_stock %}</b>
|
||||||
</div>
|
</div>
|
||||||
<div class='col-sm-2'>
|
<div class='col-sm-2'>
|
||||||
<b>{% multiply build.quantity item.quantity %}</b>
|
<b>{% multiply build.quantity item.quantity %}</b>
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
{% extends "modal_delete_form.html" %}
|
{% extends "modal_delete_form.html" %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% load inventree_extras %}
|
||||||
|
|
||||||
{% block pre_form_content %}
|
{% block pre_form_content %}
|
||||||
Are you sure you want to unallocate these parts?
|
{% trans "Are you sure you want to unallocate these parts?" %}
|
||||||
<br>
|
<br>
|
||||||
This will remove {{ item.quantity }} parts from build '{{ item.build.title }}'.
|
This will remove {% decimal item.quantity %} parts from build '{{ item.build.title }}'.
|
||||||
{% endblock %}
|
{% endblock %}
|
@ -1,9 +1,10 @@
|
|||||||
{% extends "modal_form.html" %}
|
{% extends "modal_form.html" %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% load inventree_extras %}
|
||||||
{% block pre_form_content %}
|
{% block pre_form_content %}
|
||||||
|
|
||||||
{{ block.super }}
|
{{ block.super }}
|
||||||
|
|
||||||
Are you sure you wish to unallocate all stock for this build?
|
{% trans "Are you sure you wish to unallocate all stock for this build?" %}
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
@ -53,7 +53,7 @@ class BuildCancel(AjaxUpdateView):
|
|||||||
|
|
||||||
model = Build
|
model = Build
|
||||||
ajax_template_name = 'build/cancel.html'
|
ajax_template_name = 'build/cancel.html'
|
||||||
ajax_form_title = 'Cancel Build'
|
ajax_form_title = _('Cancel Build')
|
||||||
context_object_name = 'build'
|
context_object_name = 'build'
|
||||||
form_class = forms.CancelBuildForm
|
form_class = forms.CancelBuildForm
|
||||||
|
|
||||||
@ -71,12 +71,12 @@ class BuildCancel(AjaxUpdateView):
|
|||||||
if confirm:
|
if confirm:
|
||||||
build.cancelBuild(request.user)
|
build.cancelBuild(request.user)
|
||||||
else:
|
else:
|
||||||
form.errors['confirm_cancel'] = ['Confirm build cancellation']
|
form.errors['confirm_cancel'] = [_('Confirm build cancellation')]
|
||||||
valid = False
|
valid = False
|
||||||
|
|
||||||
data = {
|
data = {
|
||||||
'form_valid': valid,
|
'form_valid': valid,
|
||||||
'danger': 'Build was cancelled'
|
'danger': _('Build was cancelled')
|
||||||
}
|
}
|
||||||
|
|
||||||
return self.renderJsonResponse(request, form, data=data)
|
return self.renderJsonResponse(request, form, data=data)
|
||||||
@ -92,7 +92,7 @@ class BuildAutoAllocate(AjaxUpdateView):
|
|||||||
model = Build
|
model = Build
|
||||||
form_class = forms.ConfirmBuildForm
|
form_class = forms.ConfirmBuildForm
|
||||||
context_object_name = 'build'
|
context_object_name = 'build'
|
||||||
ajax_form_title = 'Allocate Stock'
|
ajax_form_title = _('Allocate Stock')
|
||||||
ajax_template_name = 'build/auto_allocate.html'
|
ajax_template_name = 'build/auto_allocate.html'
|
||||||
|
|
||||||
def get_context_data(self, *args, **kwargs):
|
def get_context_data(self, *args, **kwargs):
|
||||||
@ -105,7 +105,7 @@ class BuildAutoAllocate(AjaxUpdateView):
|
|||||||
context['build'] = build
|
context['build'] = build
|
||||||
context['allocations'] = build.getAutoAllocations()
|
context['allocations'] = build.getAutoAllocations()
|
||||||
except Build.DoesNotExist:
|
except Build.DoesNotExist:
|
||||||
context['error'] = 'No matching build found'
|
context['error'] = _('No matching build found')
|
||||||
|
|
||||||
return context
|
return context
|
||||||
|
|
||||||
@ -124,8 +124,8 @@ class BuildAutoAllocate(AjaxUpdateView):
|
|||||||
valid = False
|
valid = False
|
||||||
|
|
||||||
if confirm is False:
|
if confirm is False:
|
||||||
form.errors['confirm'] = ['Confirm stock allocation']
|
form.errors['confirm'] = [_('Confirm stock allocation')]
|
||||||
form.non_field_errors = 'Check the confirmation box at the bottom of the list'
|
form.non_field_errors = _('Check the confirmation box at the bottom of the list')
|
||||||
else:
|
else:
|
||||||
build.autoAllocate()
|
build.autoAllocate()
|
||||||
valid = True
|
valid = True
|
||||||
@ -145,7 +145,7 @@ class BuildUnallocate(AjaxUpdateView):
|
|||||||
|
|
||||||
model = Build
|
model = Build
|
||||||
form_class = forms.ConfirmBuildForm
|
form_class = forms.ConfirmBuildForm
|
||||||
ajax_form_title = "Unallocate Stock"
|
ajax_form_title = _("Unallocate Stock")
|
||||||
ajax_template_name = "build/unallocate.html"
|
ajax_template_name = "build/unallocate.html"
|
||||||
|
|
||||||
def post(self, request, *args, **kwargs):
|
def post(self, request, *args, **kwargs):
|
||||||
@ -158,8 +158,8 @@ class BuildUnallocate(AjaxUpdateView):
|
|||||||
valid = False
|
valid = False
|
||||||
|
|
||||||
if confirm is False:
|
if confirm is False:
|
||||||
form.errors['confirm'] = ['Confirm unallocation of build stock']
|
form.errors['confirm'] = [_('Confirm unallocation of build stock')]
|
||||||
form.non_field_errors = 'Check the confirmation box'
|
form.non_field_errors = _('Check the confirmation box')
|
||||||
else:
|
else:
|
||||||
build.unallocateStock()
|
build.unallocateStock()
|
||||||
valid = True
|
valid = True
|
||||||
@ -182,7 +182,7 @@ class BuildComplete(AjaxUpdateView):
|
|||||||
model = Build
|
model = Build
|
||||||
form_class = forms.CompleteBuildForm
|
form_class = forms.CompleteBuildForm
|
||||||
context_object_name = "build"
|
context_object_name = "build"
|
||||||
ajax_form_title = "Complete Build"
|
ajax_form_title = _("Complete Build")
|
||||||
ajax_template_name = "build/complete.html"
|
ajax_template_name = "build/complete.html"
|
||||||
|
|
||||||
def get_form(self):
|
def get_form(self):
|
||||||
@ -255,14 +255,14 @@ class BuildComplete(AjaxUpdateView):
|
|||||||
|
|
||||||
if confirm is False:
|
if confirm is False:
|
||||||
form.errors['confirm'] = [
|
form.errors['confirm'] = [
|
||||||
'Confirm completion of build',
|
_('Confirm completion of build'),
|
||||||
]
|
]
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
location = StockLocation.objects.get(id=loc_id)
|
location = StockLocation.objects.get(id=loc_id)
|
||||||
valid = True
|
valid = True
|
||||||
except StockLocation.DoesNotExist:
|
except StockLocation.DoesNotExist:
|
||||||
form.errors['location'] = ['Invalid location selected']
|
form.errors['location'] = [_('Invalid location selected')]
|
||||||
|
|
||||||
serials = []
|
serials = []
|
||||||
|
|
||||||
@ -306,7 +306,7 @@ class BuildComplete(AjaxUpdateView):
|
|||||||
def get_data(self):
|
def get_data(self):
|
||||||
""" Provide feedback data back to the form """
|
""" Provide feedback data back to the form """
|
||||||
return {
|
return {
|
||||||
'info': 'Build marked as COMPLETE'
|
'info': _('Build marked as COMPLETE')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -382,7 +382,7 @@ class BuildCreate(AjaxCreateView):
|
|||||||
model = Build
|
model = Build
|
||||||
context_object_name = 'build'
|
context_object_name = 'build'
|
||||||
form_class = forms.EditBuildForm
|
form_class = forms.EditBuildForm
|
||||||
ajax_form_title = 'Start new Build'
|
ajax_form_title = _('Start new Build')
|
||||||
ajax_template_name = 'modal_form.html'
|
ajax_template_name = 'modal_form.html'
|
||||||
|
|
||||||
def get_initial(self):
|
def get_initial(self):
|
||||||
@ -405,7 +405,7 @@ class BuildCreate(AjaxCreateView):
|
|||||||
|
|
||||||
def get_data(self):
|
def get_data(self):
|
||||||
return {
|
return {
|
||||||
'success': 'Created new build',
|
'success': _('Created new build'),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -415,12 +415,12 @@ class BuildUpdate(AjaxUpdateView):
|
|||||||
model = Build
|
model = Build
|
||||||
form_class = forms.EditBuildForm
|
form_class = forms.EditBuildForm
|
||||||
context_object_name = 'build'
|
context_object_name = 'build'
|
||||||
ajax_form_title = 'Edit Build Details'
|
ajax_form_title = _('Edit Build Details')
|
||||||
ajax_template_name = 'modal_form.html'
|
ajax_template_name = 'modal_form.html'
|
||||||
|
|
||||||
def get_data(self):
|
def get_data(self):
|
||||||
return {
|
return {
|
||||||
'info': 'Edited build',
|
'info': _('Edited build'),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -429,7 +429,7 @@ class BuildDelete(AjaxDeleteView):
|
|||||||
|
|
||||||
model = Build
|
model = Build
|
||||||
ajax_template_name = 'build/delete_build.html'
|
ajax_template_name = 'build/delete_build.html'
|
||||||
ajax_form_title = 'Delete Build'
|
ajax_form_title = _('Delete Build')
|
||||||
|
|
||||||
|
|
||||||
class BuildItemDelete(AjaxDeleteView):
|
class BuildItemDelete(AjaxDeleteView):
|
||||||
@ -439,12 +439,12 @@ class BuildItemDelete(AjaxDeleteView):
|
|||||||
|
|
||||||
model = BuildItem
|
model = BuildItem
|
||||||
ajax_template_name = 'build/delete_build_item.html'
|
ajax_template_name = 'build/delete_build_item.html'
|
||||||
ajax_form_title = 'Unallocate Stock'
|
ajax_form_title = _('Unallocate Stock')
|
||||||
context_object_name = 'item'
|
context_object_name = 'item'
|
||||||
|
|
||||||
def get_data(self):
|
def get_data(self):
|
||||||
return {
|
return {
|
||||||
'danger': 'Removed parts from build allocation'
|
'danger': _('Removed parts from build allocation')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -454,7 +454,7 @@ class BuildItemCreate(AjaxCreateView):
|
|||||||
model = BuildItem
|
model = BuildItem
|
||||||
form_class = forms.EditBuildItemForm
|
form_class = forms.EditBuildItemForm
|
||||||
ajax_template_name = 'build/create_build_item.html'
|
ajax_template_name = 'build/create_build_item.html'
|
||||||
ajax_form_title = 'Allocate new Part'
|
ajax_form_title = _('Allocate new Part')
|
||||||
|
|
||||||
part = None
|
part = None
|
||||||
available_stock = None
|
available_stock = None
|
||||||
@ -570,11 +570,11 @@ class BuildItemEdit(AjaxUpdateView):
|
|||||||
model = BuildItem
|
model = BuildItem
|
||||||
ajax_template_name = 'modal_form.html'
|
ajax_template_name = 'modal_form.html'
|
||||||
form_class = forms.EditBuildItemForm
|
form_class = forms.EditBuildItemForm
|
||||||
ajax_form_title = 'Edit Stock Allocation'
|
ajax_form_title = _('Edit Stock Allocation')
|
||||||
|
|
||||||
def get_data(self):
|
def get_data(self):
|
||||||
return {
|
return {
|
||||||
'info': 'Updated Build Item',
|
'info': _('Updated Build Item'),
|
||||||
}
|
}
|
||||||
|
|
||||||
def get_form(self):
|
def get_form(self):
|
||||||
|
@ -5,6 +5,8 @@ Django views for interacting with common models
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.utils.translation import ugettext as _
|
||||||
|
|
||||||
from InvenTree.views import AjaxCreateView, AjaxUpdateView, AjaxDeleteView
|
from InvenTree.views import AjaxCreateView, AjaxUpdateView, AjaxDeleteView
|
||||||
|
|
||||||
from . import models
|
from . import models
|
||||||
@ -16,7 +18,7 @@ class CurrencyCreate(AjaxCreateView):
|
|||||||
|
|
||||||
model = models.Currency
|
model = models.Currency
|
||||||
form_class = forms.CurrencyEditForm
|
form_class = forms.CurrencyEditForm
|
||||||
ajax_form_title = 'Create new Currency'
|
ajax_form_title = _('Create new Currency')
|
||||||
|
|
||||||
|
|
||||||
class CurrencyEdit(AjaxUpdateView):
|
class CurrencyEdit(AjaxUpdateView):
|
||||||
@ -24,12 +26,12 @@ class CurrencyEdit(AjaxUpdateView):
|
|||||||
|
|
||||||
model = models.Currency
|
model = models.Currency
|
||||||
form_class = forms.CurrencyEditForm
|
form_class = forms.CurrencyEditForm
|
||||||
ajax_form_title = 'Edit Currency'
|
ajax_form_title = _('Edit Currency')
|
||||||
|
|
||||||
|
|
||||||
class CurrencyDelete(AjaxDeleteView):
|
class CurrencyDelete(AjaxDeleteView):
|
||||||
""" View for deleting an existing Currency object """
|
""" View for deleting an existing Currency object """
|
||||||
|
|
||||||
model = models.Currency
|
model = models.Currency
|
||||||
ajax_form_title = 'Delete Currency'
|
ajax_form_title = _('Delete Currency')
|
||||||
ajax_template_name = "common/delete_currency.html"
|
ajax_template_name = "common/delete_currency.html"
|
||||||
|
@ -1,172 +0,0 @@
|
|||||||
{% extends "base.html" %}
|
|
||||||
{% load static %}
|
|
||||||
{% load i18n %}
|
|
||||||
|
|
||||||
{% block page_title %}
|
|
||||||
InvenTree | {{ company.name }} - {% trans "Parts" %}
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
|
|
||||||
<div class='row'>
|
|
||||||
<div class='col-sm-6'>
|
|
||||||
<h3>{% trans "Supplier Part" %}</h3>
|
|
||||||
<div class='btn-row'>
|
|
||||||
<div class='btn-group'>
|
|
||||||
<button type='button' class='btn btn-default btn-glyph' id='edit-part' title='Edit supplier part'>
|
|
||||||
<span class='glyphicon glyphicon-edit'/>
|
|
||||||
</button>
|
|
||||||
<button type='button' class='btn btn-default btn-glyph' id='delete-part' title='Delete supplier part'>
|
|
||||||
<span class='glyphicon glyphicon-trash'/>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class='col-sm-6'>
|
|
||||||
<div class='media-left'>
|
|
||||||
<img class='part-thumb'
|
|
||||||
{% if part.part.image %}
|
|
||||||
src='{{ part.part.image.url }}'
|
|
||||||
{% else %}
|
|
||||||
src="{% static 'img/blank_image.png' %}"
|
|
||||||
{% endif %}/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<div class='row'>
|
|
||||||
<div class='col-sm-6'>
|
|
||||||
<h4>{% trans "Supplier Part Details" %}</h4>
|
|
||||||
<table class="table table-striped table-condensed">
|
|
||||||
<tr>
|
|
||||||
<td>{% trans "Internal Part" %}</td>
|
|
||||||
<td>
|
|
||||||
{% if part.part %}
|
|
||||||
<a href="{% url 'part-suppliers' part.part.id %}">{{ part.part.full_name }}</a>
|
|
||||||
{% endif %}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr><td>{% trans "Supplier" %}</td><td><a href="{% url 'company-detail-parts' part.supplier.id %}">{{ part.supplier.name }}</a></td></tr>
|
|
||||||
<tr><td>{% trans "SKU" %}</td><td>{{ part.SKU }}</tr></tr>
|
|
||||||
{% if part.URL %}
|
|
||||||
<tr><td>{% trans "URL" %}</td><td><a href="{{ part.URL }}">{{ part.URL }}</a></td></tr>
|
|
||||||
{% endif %}
|
|
||||||
{% if part.description %}
|
|
||||||
<tr><td>{% trans "Description" %}</td><td>{{ part.description }}</td></tr>
|
|
||||||
{% endif %}
|
|
||||||
{% if part.manufacturer %}
|
|
||||||
<tr><td>{% trans "Manufacturer" %}</td><td>{{ part.manufacturer }}</td></tr>
|
|
||||||
<tr><td>{% trans "MPN" %}</td><td>{{ part.MPN }}</td></tr>
|
|
||||||
{% endif %}
|
|
||||||
{% if part.note %}
|
|
||||||
<tr><td>{% trans "Note" %}</td><td>{{ part.note }}</td></tr>
|
|
||||||
{% endif %}
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class='col-sm-6'>
|
|
||||||
<h4>{% trans "Pricing Information" %}</h4>
|
|
||||||
<table class="table table-striped table-condensed">
|
|
||||||
<tr><td>{% trans "Order Multiple" %}</td><td>{{ part.multiple }}</td></tr>
|
|
||||||
{% if part.base_cost > 0 %}
|
|
||||||
<tr><td>{% trans "Base Price (Flat Fee)" %}</td><td>{{ part.base_cost }}</td></tr>
|
|
||||||
{% endif %}
|
|
||||||
<tr>
|
|
||||||
<th>{% trans "Price Breaks" %}</th>
|
|
||||||
<th>
|
|
||||||
<div style='float: right;'>
|
|
||||||
<button class='btn btn-primary' id='new-price-break' type='button'>{% trans "New Price Break" %}</button>
|
|
||||||
</div>
|
|
||||||
</th>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th>{% trans "Quantity" %}</th>
|
|
||||||
<th>{% trans "Price" %}</th>
|
|
||||||
</tr>
|
|
||||||
{% if part.price_breaks.all %}
|
|
||||||
{% for pb in part.price_breaks.all %}
|
|
||||||
<tr>
|
|
||||||
<td>{{ pb.quantity }}</td>
|
|
||||||
<td>
|
|
||||||
{% if pb.currency %}{{ pb.currency.symbol }}{% endif %}
|
|
||||||
{{ pb.cost }}
|
|
||||||
{% if pb.currency %}{{ pb.currency.suffix }}{% endif %}
|
|
||||||
<div class='btn-group' style='float: right;'>
|
|
||||||
<button title='Edit Price Break' class='btn btn-default btn-sm pb-edit-button' type='button' url="{% url 'price-break-edit' pb.id %}"><span class='glyphicon glyphicon-edit'></span></button>
|
|
||||||
<button title='Delete Price Break' class='btn btn-default btn-sm pb-delete-button' type='button' url="{% url 'price-break-delete' pb.id %}"><span class='glyphicon glyphicon-trash'></span></button>
|
|
||||||
</div>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
{% else %}
|
|
||||||
<tr>
|
|
||||||
<td colspan='2'>
|
|
||||||
<span class='warning-msg'><i>{% trans "No price breaks have been added for this part" %}</i></span>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{% endif %}
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
<h4>{% trans "Purchase Orders" %}</h4>
|
|
||||||
{% include "order/po_table.html" with orders=part.purchase_orders %}
|
|
||||||
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block js_ready %}
|
|
||||||
{{ block.super }}
|
|
||||||
$('#edit-part').click(function () {
|
|
||||||
launchModalForm(
|
|
||||||
"{% url 'supplier-part-edit' part.id %}",
|
|
||||||
{
|
|
||||||
reload: true
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
$('#delete-part').click(function() {
|
|
||||||
launchModalForm(
|
|
||||||
"{% url 'supplier-part-delete' %}?part={{ part.id }}",
|
|
||||||
{
|
|
||||||
redirect: "{% url 'company-detail-parts' part.supplier.id %}"
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
$('#new-price-break').click(function() {
|
|
||||||
launchModalForm("{% url 'price-break-create' %}",
|
|
||||||
{
|
|
||||||
reload: true,
|
|
||||||
data: {
|
|
||||||
part: {{ part.id }},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
$('.pb-edit-button').click(function() {
|
|
||||||
var button = $(this);
|
|
||||||
|
|
||||||
launchModalForm(button.attr('url'),
|
|
||||||
{
|
|
||||||
reload: true,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
$('.pb-delete-button').click(function() {
|
|
||||||
var button = $(this);
|
|
||||||
|
|
||||||
launchModalForm(button.attr('url'),
|
|
||||||
{
|
|
||||||
reload: true,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
{% endblock %}
|
|
68
InvenTree/company/templates/company/supplier_part_base.html
Normal file
68
InvenTree/company/templates/company/supplier_part_base.html
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
{% load static %}
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% block page_title %}
|
||||||
|
InvenTree | {% trans "Supplier Part" %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<div class='row'>
|
||||||
|
<div class='col-sm-6'>
|
||||||
|
<h3>{% trans "Supplier Part" %}</h3>
|
||||||
|
<div class='btn-row'>
|
||||||
|
<div class='btn-group'>
|
||||||
|
<button type='button' class='btn btn-default btn-glyph' id='edit-part' title='Edit supplier part'>
|
||||||
|
<span class='glyphicon glyphicon-edit'/>
|
||||||
|
</button>
|
||||||
|
<button type='button' class='btn btn-default btn-glyph' id='delete-part' title='Delete supplier part'>
|
||||||
|
<span class='glyphicon glyphicon-trash'/>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class='col-sm-6'>
|
||||||
|
<div class='media-left'>
|
||||||
|
<img class='part-thumb'
|
||||||
|
{% if part.part.image %}
|
||||||
|
src='{{ part.part.image.url }}'
|
||||||
|
{% else %}
|
||||||
|
src="{% static 'img/blank_image.png' %}"
|
||||||
|
{% endif %}/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<div class='container-fluid'>
|
||||||
|
{% block details %}
|
||||||
|
<!-- Particular SupplierPart page goes here ... -->
|
||||||
|
{% endblock %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block js_ready %}
|
||||||
|
{{ block.super }}
|
||||||
|
|
||||||
|
$('#edit-part').click(function () {
|
||||||
|
launchModalForm(
|
||||||
|
"{% url 'supplier-part-edit' part.id %}",
|
||||||
|
{
|
||||||
|
reload: true
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#delete-part').click(function() {
|
||||||
|
launchModalForm(
|
||||||
|
"{% url 'supplier-part-delete' %}?part={{ part.id }}",
|
||||||
|
{
|
||||||
|
redirect: "{% url 'company-detail-parts' part.supplier.id %}"
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
{% endblock %}
|
@ -0,0 +1,44 @@
|
|||||||
|
{% extends "company/supplier_part_base.html" %}
|
||||||
|
{% load static %}
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% block details %}
|
||||||
|
|
||||||
|
{% include "company/supplier_part_tabs.html" with tab='details' %}
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<h4>{% trans "Supplier Part Details" %}</h4>
|
||||||
|
<table class="table table-striped table-condensed">
|
||||||
|
<tr>
|
||||||
|
<td>{% trans "Internal Part" %}</td>
|
||||||
|
<td>
|
||||||
|
{% if part.part %}
|
||||||
|
<a href="{% url 'part-suppliers' part.part.id %}">{{ part.part.full_name }}</a>
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr><td>{% trans "Supplier" %}</td><td><a href="{% url 'company-detail-parts' part.supplier.id %}">{{ part.supplier.name }}</a></td></tr>
|
||||||
|
<tr><td>{% trans "SKU" %}</td><td>{{ part.SKU }}</tr></tr>
|
||||||
|
{% if part.URL %}
|
||||||
|
<tr><td>{% trans "URL" %}</td><td><a href="{{ part.URL }}">{{ part.URL }}</a></td></tr>
|
||||||
|
{% endif %}
|
||||||
|
{% if part.description %}
|
||||||
|
<tr><td>{% trans "Description" %}</td><td>{{ part.description }}</td></tr>
|
||||||
|
{% endif %}
|
||||||
|
{% if part.manufacturer %}
|
||||||
|
<tr><td>{% trans "Manufacturer" %}</td><td>{{ part.manufacturer }}</td></tr>
|
||||||
|
<tr><td>{% trans "MPN" %}</td><td>{{ part.MPN }}</td></tr>
|
||||||
|
{% endif %}
|
||||||
|
{% if part.note %}
|
||||||
|
<tr><td>{% trans "Note" %}</td><td>{{ part.note }}</td></tr>
|
||||||
|
{% endif %}
|
||||||
|
</table>
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block js_ready %}
|
||||||
|
{{ block.super }}
|
||||||
|
|
||||||
|
|
||||||
|
{% endblock %}
|
@ -0,0 +1,31 @@
|
|||||||
|
{% extends "company/supplier_part_base.html" %}
|
||||||
|
{% load static %}
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% block details %}
|
||||||
|
|
||||||
|
{% include "company/supplier_part_tabs.html" with tab='orders' %}
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<h4>{% trans "Supplier Part Orders" %}</h4>
|
||||||
|
|
||||||
|
<div id='button-bar'>
|
||||||
|
<div class='btn-group'>
|
||||||
|
<button class='btn btn-primary' type='button' id='part-order2' title='Order part'>Order Part</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<table class='table table-striped table-condensed po-table' id='purchase-order-table' data-toolbar='#button-bar'>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block js_ready %}
|
||||||
|
{{ block.super }}
|
||||||
|
|
||||||
|
loadPurchaseOrderTable($("#purchase-order-table"), {
|
||||||
|
url: "{% url 'api-po-list' %}?supplier_part={{ part.id }}",
|
||||||
|
});
|
||||||
|
|
||||||
|
{% endblock %}
|
@ -0,0 +1,92 @@
|
|||||||
|
{% extends "company/supplier_part_base.html" %}
|
||||||
|
{% load static %}
|
||||||
|
{% load i18n %}
|
||||||
|
{% load inventree_extras %}
|
||||||
|
|
||||||
|
{% block details %}
|
||||||
|
|
||||||
|
{% include "company/supplier_part_tabs.html" with tab='pricing' %}
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<h4>{% trans "Pricing Information" %}</h4>
|
||||||
|
<table class="table table-striped table-condensed">
|
||||||
|
<tr><td>{% trans "Order Multiple" %}</td><td>{{ part.multiple }}</td></tr>
|
||||||
|
{% if part.base_cost > 0 %}
|
||||||
|
<tr><td>{% trans "Base Price (Flat Fee)" %}</td><td>{{ part.base_cost }}</td></tr>
|
||||||
|
{% endif %}
|
||||||
|
<tr>
|
||||||
|
<th>{% trans "Price Breaks" %}</th>
|
||||||
|
<th>
|
||||||
|
<div style='float: right;'>
|
||||||
|
<button class='btn btn-primary' id='new-price-break' type='button'>{% trans "New Price Break" %}</button>
|
||||||
|
</div>
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>{% trans "Quantity" %}</th>
|
||||||
|
<th>{% trans "Price" %}</th>
|
||||||
|
</tr>
|
||||||
|
{% if part.price_breaks.all %}
|
||||||
|
{% for pb in part.price_breaks.all %}
|
||||||
|
<tr>
|
||||||
|
<td>{% decimal pb.quantity %}</td>
|
||||||
|
<td>
|
||||||
|
{% if pb.currency %}{{ pb.currency.symbol }}{% endif %}
|
||||||
|
{% decimal pb.cost %}
|
||||||
|
{% if pb.currency %}{{ pb.currency.suffix }}{% endif %}
|
||||||
|
<div class='btn-group' style='float: right;'>
|
||||||
|
<button title='Edit Price Break' class='btn btn-default btn-sm pb-edit-button' type='button' url="{% url 'price-break-edit' pb.id %}"><span class='glyphicon glyphicon-edit'></span></button>
|
||||||
|
<button title='Delete Price Break' class='btn btn-default btn-sm pb-delete-button' type='button' url="{% url 'price-break-delete' pb.id %}"><span class='glyphicon glyphicon-trash'></span></button>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
{% else %}
|
||||||
|
<tr>
|
||||||
|
<td colspan='2'>
|
||||||
|
<span class='warning-msg'><i>{% trans "No price breaks have been added for this part" %}</i></span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endif %}
|
||||||
|
</table>
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block js_ready %}
|
||||||
|
{{ block.super }}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
$('#new-price-break').click(function() {
|
||||||
|
launchModalForm("{% url 'price-break-create' %}",
|
||||||
|
{
|
||||||
|
reload: true,
|
||||||
|
data: {
|
||||||
|
part: {{ part.id }},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
$('.pb-edit-button').click(function() {
|
||||||
|
var button = $(this);
|
||||||
|
|
||||||
|
launchModalForm(button.attr('url'),
|
||||||
|
{
|
||||||
|
reload: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
$('.pb-delete-button').click(function() {
|
||||||
|
var button = $(this);
|
||||||
|
|
||||||
|
launchModalForm(button.attr('url'),
|
||||||
|
{
|
||||||
|
reload: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
{% endblock %}
|
72
InvenTree/company/templates/company/supplier_part_stock.html
Normal file
72
InvenTree/company/templates/company/supplier_part_stock.html
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
{% extends "company/supplier_part_base.html" %}
|
||||||
|
{% load static %}
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% block details %}
|
||||||
|
|
||||||
|
{% include "company/supplier_part_tabs.html" with tab='stock' %}
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<h4>{% trans "Supplier Part Stock" %}</h4>
|
||||||
|
|
||||||
|
{% include "stock_table.html" %}
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block js_load %}
|
||||||
|
{{ block.super }}
|
||||||
|
<script type='text/javascript' src="{% static 'script/inventree/stock.js' %}"></script>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block js_ready %}
|
||||||
|
{{ block.super }}
|
||||||
|
|
||||||
|
loadStockTable($("#stock-table"), {
|
||||||
|
params: {
|
||||||
|
supplier_part: {{ part.id }},
|
||||||
|
location_detail: true,
|
||||||
|
part_detail: true,
|
||||||
|
},
|
||||||
|
groupByField: 'location',
|
||||||
|
buttons: ['#stock-options'],
|
||||||
|
url: "{% url 'api-stock-list' %}",
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#stock-export").click(function() {
|
||||||
|
launchModalForm("{% url 'stock-export-options' %}", {
|
||||||
|
submit_text: '{% trans "Export" %}',
|
||||||
|
success: function(response) {
|
||||||
|
var url = "{% url 'stock-export' %}";
|
||||||
|
|
||||||
|
url += "?format=" + response.format;
|
||||||
|
url += "&cascade=" + response.cascade;
|
||||||
|
url += "&supplier_part={{ part.id }}";
|
||||||
|
|
||||||
|
location.href = url;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#item-create").click(function() {
|
||||||
|
launchModalForm("{% url 'stock-item-create' %}", {
|
||||||
|
reload: true,
|
||||||
|
data: {
|
||||||
|
part: {{ part.part.id }},
|
||||||
|
supplier_part: {{ part.id }},
|
||||||
|
},
|
||||||
|
secondary: [
|
||||||
|
{
|
||||||
|
field: 'location',
|
||||||
|
label: '{% trans "New Location" %}',
|
||||||
|
title: '{% trans "Create New Location" %}',
|
||||||
|
url: "{% url 'stock-location-create' %}",
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
{% endblock %}
|
16
InvenTree/company/templates/company/supplier_part_tabs.html
Normal file
16
InvenTree/company/templates/company/supplier_part_tabs.html
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
<ul class='nav nav-tabs'>
|
||||||
|
<li{% if tab == 'details' %} class='active'{% endif %}>
|
||||||
|
<a href="{% url 'supplier-part-detail' part.id %}">{% trans "Details" %}</a>
|
||||||
|
</li>
|
||||||
|
<li{% if tab == 'pricing' %} class='active'{% endif %}>
|
||||||
|
<a href="{% url 'supplier-part-pricing' part.id %}">{% trans "Pricing" %}</a>
|
||||||
|
</li>
|
||||||
|
<li{% if tab == 'stock' %} class='active'{% endif %}>
|
||||||
|
<a href="{% url 'supplier-part-stock' part.id %}">{% trans "Stock" %}</a>
|
||||||
|
</li>
|
||||||
|
<li {% if tab == 'orders' %} class='active'{% endif %}>
|
||||||
|
<a href="{% url 'supplier-part-orders' part.id %}">{% trans "Orders" %}</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
@ -47,7 +47,11 @@ price_break_urls = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
supplier_part_detail_urls = [
|
supplier_part_detail_urls = [
|
||||||
url(r'edit/?', views.SupplierPartEdit.as_view(), name='supplier-part-edit'),
|
url(r'^edit/?', views.SupplierPartEdit.as_view(), name='supplier-part-edit'),
|
||||||
|
|
||||||
|
url(r'^pricing/', views.SupplierPartDetail.as_view(template_name='company/supplier_part_pricing.html'), name='supplier-part-pricing'),
|
||||||
|
url(r'^orders/', views.SupplierPartDetail.as_view(template_name='company/supplier_part_orders.html'), name='supplier-part-orders'),
|
||||||
|
url(r'^stock/', views.SupplierPartDetail.as_view(template_name='company/supplier_part_stock.html'), name='supplier-part-stock'),
|
||||||
|
|
||||||
url('^.*$', views.SupplierPartDetail.as_view(), name='supplier-part-detail'),
|
url('^.*$', views.SupplierPartDetail.as_view(), name='supplier-part-detail'),
|
||||||
]
|
]
|
||||||
|
@ -6,6 +6,7 @@ Django views for interacting with Company app
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.utils.translation import ugettext as _
|
||||||
from django.views.generic import DetailView, ListView, UpdateView
|
from django.views.generic import DetailView, ListView, UpdateView
|
||||||
|
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
@ -93,12 +94,12 @@ class CompanyImage(AjaxUpdateView):
|
|||||||
""" View for uploading an image for the Company """
|
""" View for uploading an image for the Company """
|
||||||
model = Company
|
model = Company
|
||||||
ajax_template_name = 'modal_form.html'
|
ajax_template_name = 'modal_form.html'
|
||||||
ajax_form_title = 'Update Company Image'
|
ajax_form_title = _('Update Company Image')
|
||||||
form_class = CompanyImageForm
|
form_class = CompanyImageForm
|
||||||
|
|
||||||
def get_data(self):
|
def get_data(self):
|
||||||
return {
|
return {
|
||||||
'success': 'Updated company image',
|
'success': _('Updated company image'),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -108,11 +109,11 @@ class CompanyEdit(AjaxUpdateView):
|
|||||||
form_class = EditCompanyForm
|
form_class = EditCompanyForm
|
||||||
context_object_name = 'company'
|
context_object_name = 'company'
|
||||||
ajax_template_name = 'modal_form.html'
|
ajax_template_name = 'modal_form.html'
|
||||||
ajax_form_title = 'Edit Company'
|
ajax_form_title = _('Edit Company')
|
||||||
|
|
||||||
def get_data(self):
|
def get_data(self):
|
||||||
return {
|
return {
|
||||||
'info': 'Edited company information',
|
'info': _('Edited company information'),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -122,11 +123,11 @@ class CompanyCreate(AjaxCreateView):
|
|||||||
context_object_name = 'company'
|
context_object_name = 'company'
|
||||||
form_class = EditCompanyForm
|
form_class = EditCompanyForm
|
||||||
ajax_template_name = 'modal_form.html'
|
ajax_template_name = 'modal_form.html'
|
||||||
ajax_form_title = "Create new Company"
|
ajax_form_title = _("Create new Company")
|
||||||
|
|
||||||
def get_data(self):
|
def get_data(self):
|
||||||
return {
|
return {
|
||||||
'success': "Created new company",
|
'success': _("Created new company"),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -136,19 +137,19 @@ class CompanyDelete(AjaxDeleteView):
|
|||||||
model = Company
|
model = Company
|
||||||
success_url = '/company/'
|
success_url = '/company/'
|
||||||
ajax_template_name = 'company/delete.html'
|
ajax_template_name = 'company/delete.html'
|
||||||
ajax_form_title = 'Delete Company'
|
ajax_form_title = _('Delete Company')
|
||||||
context_object_name = 'company'
|
context_object_name = 'company'
|
||||||
|
|
||||||
def get_data(self):
|
def get_data(self):
|
||||||
return {
|
return {
|
||||||
'danger': 'Company was deleted',
|
'danger': _('Company was deleted'),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class SupplierPartDetail(DetailView):
|
class SupplierPartDetail(DetailView):
|
||||||
""" Detail view for SupplierPart """
|
""" Detail view for SupplierPart """
|
||||||
model = SupplierPart
|
model = SupplierPart
|
||||||
template_name = 'company/partdetail.html'
|
template_name = 'company/supplier_part_detail.html'
|
||||||
context_object_name = 'part'
|
context_object_name = 'part'
|
||||||
queryset = SupplierPart.objects.all()
|
queryset = SupplierPart.objects.all()
|
||||||
|
|
||||||
@ -166,7 +167,7 @@ class SupplierPartEdit(AjaxUpdateView):
|
|||||||
context_object_name = 'part'
|
context_object_name = 'part'
|
||||||
form_class = EditSupplierPartForm
|
form_class = EditSupplierPartForm
|
||||||
ajax_template_name = 'modal_form.html'
|
ajax_template_name = 'modal_form.html'
|
||||||
ajax_form_title = 'Edit Supplier Part'
|
ajax_form_title = _('Edit Supplier Part')
|
||||||
|
|
||||||
|
|
||||||
class SupplierPartCreate(AjaxCreateView):
|
class SupplierPartCreate(AjaxCreateView):
|
||||||
@ -175,7 +176,7 @@ class SupplierPartCreate(AjaxCreateView):
|
|||||||
model = SupplierPart
|
model = SupplierPart
|
||||||
form_class = EditSupplierPartForm
|
form_class = EditSupplierPartForm
|
||||||
ajax_template_name = 'modal_form.html'
|
ajax_template_name = 'modal_form.html'
|
||||||
ajax_form_title = 'Create new Supplier Part'
|
ajax_form_title = _('Create new Supplier Part')
|
||||||
context_object_name = 'part'
|
context_object_name = 'part'
|
||||||
|
|
||||||
def get_form(self):
|
def get_form(self):
|
||||||
@ -232,7 +233,7 @@ class SupplierPartDelete(AjaxDeleteView):
|
|||||||
|
|
||||||
success_url = '/supplier/'
|
success_url = '/supplier/'
|
||||||
ajax_template_name = 'company/partdelete.html'
|
ajax_template_name = 'company/partdelete.html'
|
||||||
ajax_form_title = 'Delete Supplier Part'
|
ajax_form_title = _('Delete Supplier Part')
|
||||||
|
|
||||||
parts = []
|
parts = []
|
||||||
|
|
||||||
@ -302,7 +303,7 @@ class PriceBreakCreate(AjaxCreateView):
|
|||||||
|
|
||||||
model = SupplierPriceBreak
|
model = SupplierPriceBreak
|
||||||
form_class = EditPriceBreakForm
|
form_class = EditPriceBreakForm
|
||||||
ajax_form_title = 'Add Price Break'
|
ajax_form_title = _('Add Price Break')
|
||||||
ajax_template_name = 'modal_form.html'
|
ajax_template_name = 'modal_form.html'
|
||||||
|
|
||||||
def get_data(self):
|
def get_data(self):
|
||||||
@ -337,7 +338,7 @@ class PriceBreakEdit(AjaxUpdateView):
|
|||||||
|
|
||||||
model = SupplierPriceBreak
|
model = SupplierPriceBreak
|
||||||
form_class = EditPriceBreakForm
|
form_class = EditPriceBreakForm
|
||||||
ajax_form_title = 'Edit Price Break'
|
ajax_form_title = _('Edit Price Break')
|
||||||
ajax_template_name = 'modal_form.html'
|
ajax_template_name = 'modal_form.html'
|
||||||
|
|
||||||
def get_form(self):
|
def get_form(self):
|
||||||
@ -352,5 +353,5 @@ class PriceBreakDelete(AjaxDeleteView):
|
|||||||
""" View for deleting a supplier price break """
|
""" View for deleting a supplier price break """
|
||||||
|
|
||||||
model = SupplierPriceBreak
|
model = SupplierPriceBreak
|
||||||
ajax_form_title = "Delete Price Break"
|
ajax_form_title = _("Delete Price Break")
|
||||||
ajax_template_name = 'modal_delete_form.html'
|
ajax_template_name = 'modal_delete_form.html'
|
||||||
|
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
@ -18,6 +18,7 @@ from InvenTree.status_codes import OrderStatus
|
|||||||
import os
|
import os
|
||||||
|
|
||||||
from part.models import Part
|
from part.models import Part
|
||||||
|
from company.models import SupplierPart
|
||||||
|
|
||||||
from .models import PurchaseOrder, PurchaseOrderLineItem
|
from .models import PurchaseOrder, PurchaseOrderLineItem
|
||||||
from .serializers import POSerializer, POLineItemSerializer
|
from .serializers import POSerializer, POLineItemSerializer
|
||||||
@ -62,6 +63,14 @@ class POList(generics.ListCreateAPIView):
|
|||||||
except (Part.DoesNotExist, ValueError):
|
except (Part.DoesNotExist, ValueError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
# Attempt to filter by supplier part
|
||||||
|
if 'supplier_part' in request.GET:
|
||||||
|
try:
|
||||||
|
supplier_part = SupplierPart.objects.get(pk=request.GET['supplier_part'])
|
||||||
|
queryset = queryset.filter(id__in=[p.id for p in supplier_part.purchase_orders()])
|
||||||
|
except (ValueError, SupplierPart.DoesNotExist):
|
||||||
|
pass
|
||||||
|
|
||||||
data = queryset.values(
|
data = queryset.values(
|
||||||
'pk',
|
'pk',
|
||||||
'supplier',
|
'supplier',
|
||||||
|
@ -96,7 +96,7 @@ class PurchaseOrderCreate(AjaxCreateView):
|
|||||||
""" View for creating a new PurchaseOrder object using a modal form """
|
""" View for creating a new PurchaseOrder object using a modal form """
|
||||||
|
|
||||||
model = PurchaseOrder
|
model = PurchaseOrder
|
||||||
ajax_form_title = "Create Purchase Order"
|
ajax_form_title = _("Create Purchase Order")
|
||||||
form_class = order_forms.EditPurchaseOrderForm
|
form_class = order_forms.EditPurchaseOrderForm
|
||||||
|
|
||||||
def get_initial(self):
|
def get_initial(self):
|
||||||
@ -126,7 +126,7 @@ class PurchaseOrderEdit(AjaxUpdateView):
|
|||||||
""" View for editing a PurchaseOrder using a modal form """
|
""" View for editing a PurchaseOrder using a modal form """
|
||||||
|
|
||||||
model = PurchaseOrder
|
model = PurchaseOrder
|
||||||
ajax_form_title = 'Edit Purchase Order'
|
ajax_form_title = _('Edit Purchase Order')
|
||||||
form_class = order_forms.EditPurchaseOrderForm
|
form_class = order_forms.EditPurchaseOrderForm
|
||||||
|
|
||||||
def get_form(self):
|
def get_form(self):
|
||||||
@ -146,7 +146,7 @@ class PurchaseOrderCancel(AjaxUpdateView):
|
|||||||
""" View for cancelling a purchase order """
|
""" View for cancelling a purchase order """
|
||||||
|
|
||||||
model = PurchaseOrder
|
model = PurchaseOrder
|
||||||
ajax_form_title = 'Cancel Order'
|
ajax_form_title = _('Cancel Order')
|
||||||
ajax_template_name = 'order/order_cancel.html'
|
ajax_template_name = 'order/order_cancel.html'
|
||||||
form_class = order_forms.CancelPurchaseOrderForm
|
form_class = order_forms.CancelPurchaseOrderForm
|
||||||
|
|
||||||
@ -179,7 +179,7 @@ class PurchaseOrderIssue(AjaxUpdateView):
|
|||||||
""" View for changing a purchase order from 'PENDING' to 'ISSUED' """
|
""" View for changing a purchase order from 'PENDING' to 'ISSUED' """
|
||||||
|
|
||||||
model = PurchaseOrder
|
model = PurchaseOrder
|
||||||
ajax_form_title = 'Issue Order'
|
ajax_form_title = _('Issue Order')
|
||||||
ajax_template_name = "order/order_issue.html"
|
ajax_template_name = "order/order_issue.html"
|
||||||
form_class = order_forms.IssuePurchaseOrderForm
|
form_class = order_forms.IssuePurchaseOrderForm
|
||||||
|
|
||||||
@ -215,7 +215,7 @@ class PurchaseOrderComplete(AjaxUpdateView):
|
|||||||
form_class = order_forms.CompletePurchaseOrderForm
|
form_class = order_forms.CompletePurchaseOrderForm
|
||||||
model = PurchaseOrder
|
model = PurchaseOrder
|
||||||
ajax_template_name = "order/order_complete.html"
|
ajax_template_name = "order/order_complete.html"
|
||||||
ajax_form_title = "Complete Order"
|
ajax_form_title = _("Complete Order")
|
||||||
context_object_name = 'order'
|
context_object_name = 'order'
|
||||||
|
|
||||||
def get_context_data(self):
|
def get_context_data(self):
|
||||||
@ -281,7 +281,7 @@ class PurchaseOrderReceive(AjaxUpdateView):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
form_class = order_forms.ReceivePurchaseOrderForm
|
form_class = order_forms.ReceivePurchaseOrderForm
|
||||||
ajax_form_title = "Receive Parts"
|
ajax_form_title = _("Receive Parts")
|
||||||
ajax_template_name = "order/receive_parts.html"
|
ajax_template_name = "order/receive_parts.html"
|
||||||
|
|
||||||
# Where the parts will be going (selected in POST request)
|
# Where the parts will be going (selected in POST request)
|
||||||
@ -445,7 +445,7 @@ class OrderParts(AjaxView):
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
ajax_form_title = "Order Parts"
|
ajax_form_title = _("Order Parts")
|
||||||
ajax_template_name = 'order/order_wizard/select_parts.html'
|
ajax_template_name = 'order/order_wizard/select_parts.html'
|
||||||
|
|
||||||
# List of Parts we wish to order
|
# List of Parts we wish to order
|
||||||
@ -744,7 +744,7 @@ class POLineItemCreate(AjaxCreateView):
|
|||||||
model = PurchaseOrderLineItem
|
model = PurchaseOrderLineItem
|
||||||
context_object_name = 'line'
|
context_object_name = 'line'
|
||||||
form_class = order_forms.EditPurchaseOrderLineItemForm
|
form_class = order_forms.EditPurchaseOrderLineItemForm
|
||||||
ajax_form_title = 'Add Line Item'
|
ajax_form_title = _('Add Line Item')
|
||||||
|
|
||||||
def post(self, request, *arg, **kwargs):
|
def post(self, request, *arg, **kwargs):
|
||||||
|
|
||||||
@ -859,7 +859,7 @@ class POLineItemEdit(AjaxUpdateView):
|
|||||||
model = PurchaseOrderLineItem
|
model = PurchaseOrderLineItem
|
||||||
form_class = order_forms.EditPurchaseOrderLineItemForm
|
form_class = order_forms.EditPurchaseOrderLineItemForm
|
||||||
ajax_template_name = 'modal_form.html'
|
ajax_template_name = 'modal_form.html'
|
||||||
ajax_form_title = 'Edit Line Item'
|
ajax_form_title = _('Edit Line Item')
|
||||||
|
|
||||||
def get_form(self):
|
def get_form(self):
|
||||||
form = super().get_form()
|
form = super().get_form()
|
||||||
@ -875,10 +875,10 @@ class POLineItemDelete(AjaxDeleteView):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
model = PurchaseOrderLineItem
|
model = PurchaseOrderLineItem
|
||||||
ajax_form_title = 'Delete Line Item'
|
ajax_form_title = _('Delete Line Item')
|
||||||
ajax_template_name = 'order/po_lineitem_delete.html'
|
ajax_template_name = 'order/po_lineitem_delete.html'
|
||||||
|
|
||||||
def get_data(self):
|
def get_data(self):
|
||||||
return {
|
return {
|
||||||
'danger': 'Deleted line item',
|
'danger': _('Deleted line item'),
|
||||||
}
|
}
|
||||||
|
@ -131,11 +131,13 @@ class BomItemResource(ModelResource):
|
|||||||
|
|
||||||
level = Field(attribute='level', readonly=True)
|
level = Field(attribute='level', readonly=True)
|
||||||
|
|
||||||
part = Field(attribute='part', widget=widgets.ForeignKeyWidget(Part))
|
bom_id = Field(attribute='pk')
|
||||||
|
|
||||||
|
parent_part_id = Field(attribute='part', widget=widgets.ForeignKeyWidget(Part))
|
||||||
|
|
||||||
parent_part_name = Field(attribute='part__full_name', readonly=True)
|
parent_part_name = Field(attribute='part__full_name', readonly=True)
|
||||||
|
|
||||||
id = Field(attribute='sub_part', widget=widgets.ForeignKeyWidget(Part))
|
sub_part_id = Field(attribute='sub_part', widget=widgets.ForeignKeyWidget(Part))
|
||||||
|
|
||||||
sub_part_name = Field(attribute='sub_part__full_name', readonly=True)
|
sub_part_name = Field(attribute='sub_part__full_name', readonly=True)
|
||||||
|
|
||||||
@ -147,7 +149,12 @@ class BomItemResource(ModelResource):
|
|||||||
report_skipped = False
|
report_skipped = False
|
||||||
clean_model_instances = True
|
clean_model_instances = True
|
||||||
|
|
||||||
exclude = ['checksum', ]
|
exclude = [
|
||||||
|
'checksum',
|
||||||
|
'id',
|
||||||
|
'part',
|
||||||
|
'sub_part',
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
class BomItemAdmin(ImportExportModelAdmin):
|
class BomItemAdmin(ImportExportModelAdmin):
|
||||||
|
@ -53,12 +53,18 @@ def ExportBom(part, fmt='csv', cascade=False):
|
|||||||
|
|
||||||
bom_items = []
|
bom_items = []
|
||||||
|
|
||||||
|
uids = []
|
||||||
|
|
||||||
def add_items(items, level):
|
def add_items(items, level):
|
||||||
# Add items at a given layer
|
# Add items at a given layer
|
||||||
for item in items:
|
for item in items:
|
||||||
|
|
||||||
item.level = '-' * level
|
item.level = '-' * level
|
||||||
|
|
||||||
|
# Avoid circular BOM references
|
||||||
|
if item.pk in uids:
|
||||||
|
continue
|
||||||
|
|
||||||
bom_items.append(item)
|
bom_items.append(item)
|
||||||
|
|
||||||
if item.sub_part.assembly:
|
if item.sub_part.assembly:
|
||||||
|
@ -35,6 +35,7 @@ from InvenTree import helpers
|
|||||||
from InvenTree import validators
|
from InvenTree import validators
|
||||||
from InvenTree.models import InvenTreeTree
|
from InvenTree.models import InvenTreeTree
|
||||||
from InvenTree.fields import InvenTreeURLField
|
from InvenTree.fields import InvenTreeURLField
|
||||||
|
from InvenTree.helpers import decimal2string
|
||||||
|
|
||||||
from InvenTree.status_codes import BuildStatus, StockStatus, OrderStatus
|
from InvenTree.status_codes import BuildStatus, StockStatus, OrderStatus
|
||||||
|
|
||||||
@ -1242,11 +1243,11 @@ class BomItem(models.Model):
|
|||||||
|
|
||||||
pmin, pmax = prange
|
pmin, pmax = prange
|
||||||
|
|
||||||
# remove trailing zeros
|
|
||||||
pmin = pmin.normalize()
|
|
||||||
pmax = pmax.normalize()
|
|
||||||
|
|
||||||
if pmin == pmax:
|
if pmin == pmax:
|
||||||
return str(pmin)
|
return decimal2string(pmin)
|
||||||
|
|
||||||
|
# Convert to better string representation
|
||||||
|
pmin = decimal2string(pmin)
|
||||||
|
pmax = decimal2string(pmax)
|
||||||
|
|
||||||
return "{pmin} to {pmax}".format(pmin=pmin, pmax=pmax)
|
return "{pmin} to {pmax}".format(pmin=pmin, pmax=pmax)
|
||||||
|
@ -39,6 +39,9 @@
|
|||||||
{
|
{
|
||||||
title: 'Allocated',
|
title: 'Allocated',
|
||||||
sortable: false,
|
sortable: false,
|
||||||
|
formatter: function(value, row, index, field) {
|
||||||
|
return parseFloat(value);
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Status',
|
title: 'Status',
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
{% extends "part/part_base.html" %}
|
{% extends "part/part_base.html" %}
|
||||||
{% load static %}
|
{% load static %}
|
||||||
|
{% load i18n %}
|
||||||
{% block details %}
|
{% block details %}
|
||||||
|
|
||||||
{% include 'part/tabs.html' with tab='stock' %}
|
{% include 'part/tabs.html' with tab='stock' %}
|
||||||
@ -49,7 +50,7 @@
|
|||||||
|
|
||||||
$("#stock-export").click(function() {
|
$("#stock-export").click(function() {
|
||||||
launchModalForm("{% url 'stock-export-options' %}", {
|
launchModalForm("{% url 'stock-export-options' %}", {
|
||||||
submit_text: "Export",
|
submit_text: "{% trans 'Export' %}",
|
||||||
success: function(response) {
|
success: function(response) {
|
||||||
var url = "{% url 'stock-export' %}";
|
var url = "{% url 'stock-export' %}";
|
||||||
|
|
||||||
@ -71,14 +72,14 @@
|
|||||||
secondary: [
|
secondary: [
|
||||||
{
|
{
|
||||||
field: 'part',
|
field: 'part',
|
||||||
label: 'New Part',
|
label: '{% trans "New Part" %}',
|
||||||
title: 'Create New Part',
|
title: '{% trans "Create New Part" %}',
|
||||||
url: "{% url 'part-create' %}",
|
url: "{% url 'part-create' %}",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'supplier_part',
|
field: 'supplier_part',
|
||||||
label: 'New Supplier Part',
|
label: '{% trans "New Supplier Part" %}',
|
||||||
title: 'Create new Supplier Part',
|
title: '{% trans "Create new Supplier Part" %}',
|
||||||
url: "{% url 'supplier-part-create' %}",
|
url: "{% url 'supplier-part-create' %}",
|
||||||
data: {
|
data: {
|
||||||
part: {{ part.id }}
|
part: {{ part.id }}
|
||||||
@ -86,8 +87,8 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
field: 'location',
|
field: 'location',
|
||||||
label: 'New Location',
|
label: '{% trans "New Location" %}',
|
||||||
title: 'Create New Location',
|
title: '{% trans "Create New Location" %}',
|
||||||
url: "{% url 'stock-location-create' %}",
|
url: "{% url 'stock-location-create' %}",
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -53,6 +53,9 @@
|
|||||||
sortable: true,
|
sortable: true,
|
||||||
field: 'quantity',
|
field: 'quantity',
|
||||||
title: 'Uses',
|
title: 'Uses',
|
||||||
|
formatter: function(value, row, index, field) {
|
||||||
|
return parseFloat(value);
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
],
|
],
|
||||||
|
@ -27,7 +27,7 @@ def inrange(n, *args, **kwargs):
|
|||||||
@register.simple_tag()
|
@register.simple_tag()
|
||||||
def multiply(x, y, *args, **kwargs):
|
def multiply(x, y, *args, **kwargs):
|
||||||
""" Multiply two numbers together """
|
""" Multiply two numbers together """
|
||||||
return x * y
|
return decimal2string(x * y)
|
||||||
|
|
||||||
|
|
||||||
@register.simple_tag()
|
@register.simple_tag()
|
||||||
@ -40,7 +40,7 @@ def add(x, y, *args, **kwargs):
|
|||||||
def part_allocation_count(build, part, *args, **kwargs):
|
def part_allocation_count(build, part, *args, **kwargs):
|
||||||
""" Return the total number of <part> allocated to <build> """
|
""" Return the total number of <part> allocated to <build> """
|
||||||
|
|
||||||
return build.getAllocatedQuantity(part)
|
return decimal2string(build.getAllocatedQuantity(part))
|
||||||
|
|
||||||
|
|
||||||
@register.simple_tag()
|
@register.simple_tag()
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
# Tests for the Part model
|
# Tests for the Part model
|
||||||
|
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
@ -16,7 +17,7 @@ class TemplateTagTest(TestCase):
|
|||||||
""" Tests for the custom template tag code """
|
""" Tests for the custom template tag code """
|
||||||
|
|
||||||
def test_multiply(self):
|
def test_multiply(self):
|
||||||
self.assertEqual(inventree_extras.multiply(3, 5), 15)
|
self.assertEqual(int(inventree_extras.multiply(3, 5)), 15)
|
||||||
|
|
||||||
def test_version(self):
|
def test_version(self):
|
||||||
self.assertEqual(type(inventree_extras.inventree_version()), str)
|
self.assertEqual(type(inventree_extras.inventree_version()), str)
|
||||||
|
@ -72,7 +72,7 @@ class PartAttachmentCreate(AjaxCreateView):
|
|||||||
"""
|
"""
|
||||||
model = PartAttachment
|
model = PartAttachment
|
||||||
form_class = part_forms.EditPartAttachmentForm
|
form_class = part_forms.EditPartAttachmentForm
|
||||||
ajax_form_title = "Add part attachment"
|
ajax_form_title = _("Add part attachment")
|
||||||
ajax_template_name = "modal_form.html"
|
ajax_template_name = "modal_form.html"
|
||||||
|
|
||||||
def get_data(self):
|
def get_data(self):
|
||||||
@ -115,7 +115,7 @@ class PartAttachmentEdit(AjaxUpdateView):
|
|||||||
model = PartAttachment
|
model = PartAttachment
|
||||||
form_class = part_forms.EditPartAttachmentForm
|
form_class = part_forms.EditPartAttachmentForm
|
||||||
ajax_template_name = 'modal_form.html'
|
ajax_template_name = 'modal_form.html'
|
||||||
ajax_form_title = 'Edit attachment'
|
ajax_form_title = _('Edit attachment')
|
||||||
|
|
||||||
def get_data(self):
|
def get_data(self):
|
||||||
return {
|
return {
|
||||||
@ -134,13 +134,13 @@ class PartAttachmentDelete(AjaxDeleteView):
|
|||||||
""" View for deleting a PartAttachment """
|
""" View for deleting a PartAttachment """
|
||||||
|
|
||||||
model = PartAttachment
|
model = PartAttachment
|
||||||
ajax_form_title = "Delete Part Attachment"
|
ajax_form_title = _("Delete Part Attachment")
|
||||||
ajax_template_name = "part/attachment_delete.html"
|
ajax_template_name = "part/attachment_delete.html"
|
||||||
context_object_name = "attachment"
|
context_object_name = "attachment"
|
||||||
|
|
||||||
def get_data(self):
|
def get_data(self):
|
||||||
return {
|
return {
|
||||||
'danger': 'Deleted part attachment'
|
'danger': _('Deleted part attachment')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -148,7 +148,7 @@ class PartSetCategory(AjaxUpdateView):
|
|||||||
""" View for settings the part category for multiple parts at once """
|
""" View for settings the part category for multiple parts at once """
|
||||||
|
|
||||||
ajax_template_name = 'part/set_category.html'
|
ajax_template_name = 'part/set_category.html'
|
||||||
ajax_form_title = 'Set Part Category'
|
ajax_form_title = _('Set Part Category')
|
||||||
form_class = part_forms.SetPartCategoryForm
|
form_class = part_forms.SetPartCategoryForm
|
||||||
|
|
||||||
category = None
|
category = None
|
||||||
@ -231,7 +231,7 @@ class MakePartVariant(AjaxCreateView):
|
|||||||
model = Part
|
model = Part
|
||||||
form_class = part_forms.EditPartForm
|
form_class = part_forms.EditPartForm
|
||||||
|
|
||||||
ajax_form_title = 'Create Variant'
|
ajax_form_title = _('Create Variant')
|
||||||
ajax_template_name = 'part/variant_part.html'
|
ajax_template_name = 'part/variant_part.html'
|
||||||
|
|
||||||
def get_part_template(self):
|
def get_part_template(self):
|
||||||
@ -301,7 +301,7 @@ class PartDuplicate(AjaxCreateView):
|
|||||||
model = Part
|
model = Part
|
||||||
form_class = part_forms.EditPartForm
|
form_class = part_forms.EditPartForm
|
||||||
|
|
||||||
ajax_form_title = "Duplicate Part"
|
ajax_form_title = _("Duplicate Part")
|
||||||
ajax_template_name = "part/copy_part.html"
|
ajax_template_name = "part/copy_part.html"
|
||||||
|
|
||||||
def get_data(self):
|
def get_data(self):
|
||||||
@ -592,7 +592,7 @@ class PartDetail(DetailView):
|
|||||||
class PartQRCode(QRCodeView):
|
class PartQRCode(QRCodeView):
|
||||||
""" View for displaying a QR code for a Part object """
|
""" View for displaying a QR code for a Part object """
|
||||||
|
|
||||||
ajax_form_title = "Part QR Code"
|
ajax_form_title = _("Part QR Code")
|
||||||
|
|
||||||
def get_qr_data(self):
|
def get_qr_data(self):
|
||||||
""" Generate QR code data for the Part """
|
""" Generate QR code data for the Part """
|
||||||
|
@ -301,6 +301,7 @@ class StockList(generics.ListCreateAPIView):
|
|||||||
'part__category',
|
'part__category',
|
||||||
'part__category__name',
|
'part__category__name',
|
||||||
'part__category__description',
|
'part__category__description',
|
||||||
|
'supplier_part',
|
||||||
)
|
)
|
||||||
|
|
||||||
# Reduce the number of lookups we need to do for categories
|
# Reduce the number of lookups we need to do for categories
|
||||||
@ -371,7 +372,13 @@ class StockList(generics.ListCreateAPIView):
|
|||||||
except PartCategory.DoesNotExist:
|
except PartCategory.DoesNotExist:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# Filter by supplier
|
# Filter by supplier_part ID
|
||||||
|
supplier_part_id = self.request.query_params.get('supplier_part', None)
|
||||||
|
|
||||||
|
if supplier_part_id:
|
||||||
|
stock_list = stock_list.filter(supplier_part=supplier_part_id)
|
||||||
|
|
||||||
|
# Filter by supplier ID
|
||||||
supplier_id = self.request.query_params.get('supplier', None)
|
supplier_id = self.request.query_params.get('supplier', None)
|
||||||
|
|
||||||
if supplier_id:
|
if supplier_id:
|
||||||
|
@ -35,7 +35,9 @@
|
|||||||
<hr>
|
<hr>
|
||||||
<div class='panel panel-default'>
|
<div class='panel panel-default'>
|
||||||
<div class='panel-content'>
|
<div class='panel-content'>
|
||||||
|
{% if item.notes %}
|
||||||
{{ item.notes | markdownify }}
|
{{ item.notes | markdownify }}
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -1,26 +0,0 @@
|
|||||||
{% extends "stock/stock_app_base.html" %}
|
|
||||||
{% load static %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
|
|
||||||
<h3>Stock list here!</h3>
|
|
||||||
|
|
||||||
<table class='table table-striped table-condensed' data-toolbar='#button-toolbar' id='tracking-table'>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block js_ready %}
|
|
||||||
{{ block.super }}
|
|
||||||
|
|
||||||
loadStockTrackingTable($("#tracking-table"), {
|
|
||||||
params: function(p) {
|
|
||||||
return {
|
|
||||||
ordering: '-date',
|
|
||||||
};
|
|
||||||
},
|
|
||||||
partColumn: true,
|
|
||||||
url: "{% url 'api-stock-track' %}",
|
|
||||||
});
|
|
||||||
|
|
||||||
{% endblock %}
|
|
@ -24,7 +24,7 @@ from InvenTree.helpers import ExtractSerialNumbers
|
|||||||
from decimal import Decimal, InvalidOperation
|
from decimal import Decimal, InvalidOperation
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
from company.models import Company
|
from company.models import Company, SupplierPart
|
||||||
from part.models import Part
|
from part.models import Part
|
||||||
from .models import StockItem, StockLocation, StockItemTracking
|
from .models import StockItem, StockLocation, StockItemTracking
|
||||||
|
|
||||||
@ -212,6 +212,16 @@ class StockExport(AjaxView):
|
|||||||
except (ValueError, Company.DoesNotExist):
|
except (ValueError, Company.DoesNotExist):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
# Check if a particular supplier_part was specified
|
||||||
|
sup_part_id = request.GET.get('supplier_part', None)
|
||||||
|
supplier_part = None
|
||||||
|
|
||||||
|
if sup_part_id:
|
||||||
|
try:
|
||||||
|
supplier_part = SupplierPart.objects.get(pk=sup_part_id)
|
||||||
|
except (ValueError, SupplierPart.DoesNotExist):
|
||||||
|
pass
|
||||||
|
|
||||||
# Check if a particular part was specified
|
# Check if a particular part was specified
|
||||||
part_id = request.GET.get('part', None)
|
part_id = request.GET.get('part', None)
|
||||||
part = None
|
part = None
|
||||||
@ -244,7 +254,11 @@ class StockExport(AjaxView):
|
|||||||
if supplier:
|
if supplier:
|
||||||
stock_items = stock_items.filter(supplier_part__supplier=supplier)
|
stock_items = stock_items.filter(supplier_part__supplier=supplier)
|
||||||
|
|
||||||
|
if supplier_part:
|
||||||
|
stock_items = stock_items.filter(supplier_part=supplier_part)
|
||||||
|
|
||||||
# Filter out stock items that are not 'in stock'
|
# Filter out stock items that are not 'in stock'
|
||||||
|
# TODO - This might need some more thought in the future...
|
||||||
stock_items = stock_items.filter(customer=None)
|
stock_items = stock_items.filter(customer=None)
|
||||||
stock_items = stock_items.filter(belongs_to=None)
|
stock_items = stock_items.filter(belongs_to=None)
|
||||||
|
|
||||||
@ -816,6 +830,11 @@ class StockItemCreate(AjaxCreateView):
|
|||||||
|
|
||||||
part_id = self.request.GET.get('part', None)
|
part_id = self.request.GET.get('part', None)
|
||||||
loc_id = self.request.GET.get('location', None)
|
loc_id = self.request.GET.get('location', None)
|
||||||
|
sup_part_id = self.request.GET.get('supplier_part', None)
|
||||||
|
|
||||||
|
part = None
|
||||||
|
location = None
|
||||||
|
supplier_part = None
|
||||||
|
|
||||||
# Part field has been specified
|
# Part field has been specified
|
||||||
if part_id:
|
if part_id:
|
||||||
@ -824,14 +843,27 @@ class StockItemCreate(AjaxCreateView):
|
|||||||
initials['part'] = part
|
initials['part'] = part
|
||||||
initials['location'] = part.get_default_location()
|
initials['location'] = part.get_default_location()
|
||||||
initials['supplier_part'] = part.default_supplier
|
initials['supplier_part'] = part.default_supplier
|
||||||
except Part.DoesNotExist:
|
except (ValueError, Part.DoesNotExist):
|
||||||
|
pass
|
||||||
|
|
||||||
|
# SupplierPart field has been specified
|
||||||
|
# It must match the Part, if that has been supplied
|
||||||
|
if sup_part_id:
|
||||||
|
try:
|
||||||
|
supplier_part = SupplierPart.objects.get(pk=sup_part_id)
|
||||||
|
|
||||||
|
if part is None or supplier_part.part == part:
|
||||||
|
initials['supplier_part'] = supplier_part
|
||||||
|
|
||||||
|
except (ValueError, SupplierPart.DoesNotExist):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# Location has been specified
|
# Location has been specified
|
||||||
if loc_id:
|
if loc_id:
|
||||||
try:
|
try:
|
||||||
initials['location'] = StockLocation.objects.get(pk=loc_id)
|
location = StockLocation.objects.get(pk=loc_id)
|
||||||
except StockLocation.DoesNotExist:
|
initials['location'] = location
|
||||||
|
except (ValueError, StockLocation.DoesNotExist):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
return initials
|
return initials
|
||||||
|
@ -1,18 +1,18 @@
|
|||||||
|
{% load i18n %}
|
||||||
|
|
||||||
<div id='button-toolbar'>
|
<div id='button-toolbar'>
|
||||||
<div class='button-toolbar container-fluid' style='float: right;'>
|
<div class='button-toolbar container-fluid' style='float: right;'>
|
||||||
<button class='btn btn-default' id='stock-export' title='Export Stock Information'>Export</button>
|
<button class='btn btn-default' id='stock-export' title='Export Stock Information'>{% trans "Export" %}</button>
|
||||||
{% if not part or part.is_template == False %}
|
<button class="btn btn-success" id='item-create'>{% trans "New Stock Item" %}</button>
|
||||||
<button class="btn btn-success" id='item-create'>New Stock Item</button>
|
|
||||||
{% endif %}
|
|
||||||
<div class="dropdown" style='float: right;'>
|
<div class="dropdown" style='float: right;'>
|
||||||
<button id='stock-options' class="btn btn-primary dropdown-toggle" type="button" data-toggle="dropdown">Options<span class="caret"></span></button>
|
<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">
|
<ul class="dropdown-menu">
|
||||||
<li><a href="#" id='multi-item-add' title='Add to selected stock items'>Add stock</a></li>
|
<li><a href="#" id='multi-item-add' title='Add to selected stock items'>{% trans "Add stock" %}</a></li>
|
||||||
<li><a href="#" id='multi-item-remove' title='Remove from selected stock items'>Remove stock</a></li>
|
<li><a href="#" id='multi-item-remove' title='Remove from selected stock items'>{% trans "Remove stock" %}</a></li>
|
||||||
<li><a href="#" id='multi-item-stocktake' title='Stocktake selected stock items'>Count stock</a></li>
|
<li><a href="#" id='multi-item-stocktake' title='Stocktake selected stock items'>{% trans "Count stock" %}</a></li>
|
||||||
<li><a href='#' id='multi-item-move' title='Move selected stock items'>Move stock</a></li>
|
<li><a href='#' id='multi-item-move' title='Move selected stock items'>{% trans "Move stock" %}</a></li>
|
||||||
<li><a href='#' id='multi-item-order' title='Order selected items'>Order stock</a></li>
|
<li><a href='#' id='multi-item-order' title='Order selected items'>{% trans "Order stock" %}</a></li>
|
||||||
<li><a href='#' id='multi-item-delete' title='Delete selected items'>Delete Stock</a></li>
|
<li><a href='#' id='multi-item-delete' title='Delete selected items'>{% trans "Delete Stock" %}</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
Django==2.2.9 # Django package
|
Django==2.2.10 # Django package
|
||||||
pillow==6.2.0 # Image manipulation
|
pillow==6.2.0 # Image manipulation
|
||||||
djangorestframework==3.10.3 # DRF framework
|
djangorestframework==3.10.3 # DRF framework
|
||||||
django-cors-headers==3.2.0 # CORS headers extension for DRF
|
django-cors-headers==3.2.0 # CORS headers extension for DRF
|
||||||
|
Loading…
x
Reference in New Issue
Block a user