mirror of
https://github.com/inventree/InvenTree.git
synced 2025-06-17 04:25:42 +00:00
Merge remote-tracking branch 'inventree/master' into variant-available
# Conflicts: # InvenTree/InvenTree/version.py
This commit is contained in:
149
InvenTree/InvenTree/api_version.py
Normal file
149
InvenTree/InvenTree/api_version.py
Normal file
@ -0,0 +1,149 @@
|
||||
"""
|
||||
InvenTree API version information
|
||||
"""
|
||||
|
||||
|
||||
# InvenTree API version
|
||||
INVENTREE_API_VERSION = 40
|
||||
|
||||
"""
|
||||
Increment this API version number whenever there is a significant change to the API that any clients need to know about
|
||||
|
||||
v40 -> 2022-04-19
|
||||
- Adds ability to filter StockItem list by "tracked" parameter
|
||||
- This checks the serial number or batch code fields
|
||||
|
||||
v39 -> 2022-04-18
|
||||
- Adds ability to filter StockItem list by "has_batch" parameter
|
||||
|
||||
v38 -> 2022-04-14 : https://github.com/inventree/InvenTree/pull/2828
|
||||
- Adds the ability to include stock test results for "installed items"
|
||||
|
||||
v37 -> 2022-04-07 : https://github.com/inventree/InvenTree/pull/2806
|
||||
- Adds extra stock availability information to the BomItem serializer
|
||||
|
||||
v36 -> 2022-04-03
|
||||
- Adds ability to filter part list endpoint by unallocated_stock argument
|
||||
|
||||
v35 -> 2022-04-01 : https://github.com/inventree/InvenTree/pull/2797
|
||||
- Adds stock allocation information to the Part API
|
||||
- Adds calculated field for "unallocated_quantity"
|
||||
|
||||
v34 -> 2022-03-25
|
||||
- Change permissions for "plugin list" API endpoint (now allows any authenticated user)
|
||||
|
||||
v33 -> 2022-03-24
|
||||
- Adds "plugins_enabled" information to root API endpoint
|
||||
|
||||
v32 -> 2022-03-19
|
||||
- Adds "parameters" detail to Part API endpoint (use ¶meters=true)
|
||||
- Adds ability to filter PartParameterTemplate API by Part instance
|
||||
- Adds ability to filter PartParameterTemplate API by PartCategory instance
|
||||
|
||||
v31 -> 2022-03-14
|
||||
- Adds "updated" field to SupplierPriceBreakList and SupplierPriceBreakDetail API endpoints
|
||||
|
||||
v30 -> 2022-03-09
|
||||
- Adds "exclude_location" field to BuildAutoAllocation API endpoint
|
||||
- Allows BuildItem API endpoint to be filtered by BomItem relation
|
||||
|
||||
v29 -> 2022-03-08
|
||||
- Adds "scheduling" endpoint for predicted stock scheduling information
|
||||
|
||||
v28 -> 2022-03-04
|
||||
- Adds an API endpoint for auto allocation of stock items against a build order
|
||||
- Ref: https://github.com/inventree/InvenTree/pull/2713
|
||||
|
||||
v27 -> 2022-02-28
|
||||
- Adds target_date field to individual line items for purchase orders and sales orders
|
||||
|
||||
v26 -> 2022-02-17
|
||||
- Adds API endpoint for uploading a BOM file and extracting data
|
||||
|
||||
v25 -> 2022-02-17
|
||||
- Adds ability to filter "part" list endpoint by "in_bom_for" argument
|
||||
|
||||
v24 -> 2022-02-10
|
||||
- Adds API endpoint for deleting (cancelling) build order outputs
|
||||
|
||||
v23 -> 2022-02-02
|
||||
- Adds API endpoints for managing plugin classes
|
||||
- Adds API endpoints for managing plugin settings
|
||||
|
||||
v22 -> 2021-12-20
|
||||
- Adds API endpoint to "merge" multiple stock items
|
||||
|
||||
v21 -> 2021-12-04
|
||||
- Adds support for multiple "Shipments" against a SalesOrder
|
||||
- Refactors process for stock allocation against a SalesOrder
|
||||
|
||||
v20 -> 2021-12-03
|
||||
- Adds ability to filter POLineItem endpoint by "base_part"
|
||||
- Adds optional "order_detail" to POLineItem list endpoint
|
||||
|
||||
v19 -> 2021-12-02
|
||||
- Adds the ability to filter the StockItem API by "part_tree"
|
||||
- Returns only stock items which match a particular part.tree_id field
|
||||
|
||||
v18 -> 2021-11-15
|
||||
- Adds the ability to filter BomItem API by "uses" field
|
||||
- This returns a list of all BomItems which "use" the specified part
|
||||
- Includes inherited BomItem objects
|
||||
|
||||
v17 -> 2021-11-09
|
||||
- Adds API endpoints for GLOBAL and USER settings objects
|
||||
- Ref: https://github.com/inventree/InvenTree/pull/2275
|
||||
|
||||
v16 -> 2021-10-17
|
||||
- Adds API endpoint for completing build order outputs
|
||||
|
||||
v15 -> 2021-10-06
|
||||
- Adds detail endpoint for SalesOrderAllocation model
|
||||
- Allows use of the API forms interface for adjusting SalesOrderAllocation objects
|
||||
|
||||
v14 -> 2021-10-05
|
||||
- Stock adjustment actions API is improved, using native DRF serializer support
|
||||
- However adjustment actions now only support 'pk' as a lookup field
|
||||
|
||||
v13 -> 2021-10-05
|
||||
- Adds API endpoint to allocate stock items against a BuildOrder
|
||||
- Updates StockItem API with improved filtering against BomItem data
|
||||
|
||||
v12 -> 2021-09-07
|
||||
- Adds API endpoint to receive stock items against a PurchaseOrder
|
||||
|
||||
v11 -> 2021-08-26
|
||||
- Adds "units" field to PartBriefSerializer
|
||||
- This allows units to be introspected from the "part_detail" field in the StockItem serializer
|
||||
|
||||
v10 -> 2021-08-23
|
||||
- Adds "purchase_price_currency" to StockItem serializer
|
||||
- Adds "purchase_price_string" to StockItem serializer
|
||||
- Purchase price is now writable for StockItem serializer
|
||||
|
||||
v9 -> 2021-08-09
|
||||
- Adds "price_string" to part pricing serializers
|
||||
|
||||
v8 -> 2021-07-19
|
||||
- Refactors the API interface for SupplierPart and ManufacturerPart models
|
||||
- ManufacturerPart objects can no longer be created via the SupplierPart API endpoint
|
||||
|
||||
v7 -> 2021-07-03
|
||||
- Introduced the concept of "API forms" in https://github.com/inventree/InvenTree/pull/1716
|
||||
- API OPTIONS endpoints provide comprehensive field metedata
|
||||
- Multiple new API endpoints added for database models
|
||||
|
||||
v6 -> 2021-06-23
|
||||
- Part and Company images can now be directly uploaded via the REST API
|
||||
|
||||
v5 -> 2021-06-21
|
||||
- Adds API interface for manufacturer part parameters
|
||||
|
||||
v4 -> 2021-06-01
|
||||
- BOM items can now accept "variant stock" to be assigned against them
|
||||
- Many slight API tweaks were needed to get this to work properly!
|
||||
|
||||
v3 -> 2021-05-22:
|
||||
- The updated StockItem "history tracking" now uses a different interface
|
||||
|
||||
"""
|
@ -282,6 +282,7 @@ INSTALLED_APPS = [
|
||||
|
||||
MIDDLEWARE = CONFIG.get('middleware', [
|
||||
'django.middleware.security.SecurityMiddleware',
|
||||
'x_forwarded_for.middleware.XForwardedForMiddleware',
|
||||
'user_sessions.middleware.SessionMiddleware', # db user sessions
|
||||
'django.middleware.locale.LocaleMiddleware',
|
||||
'django.middleware.common.CommonMiddleware',
|
||||
@ -662,11 +663,13 @@ LANGUAGE_CODE = CONFIG.get('language', 'en-us')
|
||||
|
||||
# If a new language translation is supported, it must be added here
|
||||
LANGUAGES = [
|
||||
('cs', _('Czech')),
|
||||
('de', _('German')),
|
||||
('el', _('Greek')),
|
||||
('en', _('English')),
|
||||
('es', _('Spanish')),
|
||||
('es-mx', _('Spanish (Mexican)')),
|
||||
('fa', _('Farsi / Persian')),
|
||||
('fr', _('French')),
|
||||
('he', _('Hebrew')),
|
||||
('hu', _('Hungarian')),
|
||||
|
@ -1,4 +1,4 @@
|
||||
/*! jQuery UI - v1.12.1 - 2021-07-18
|
||||
/*! jQuery UI - v1.13.0 - 2021-10-07
|
||||
* http://jqueryui.com
|
||||
* Includes: widget.js, position.js, disable-selection.js, keycode.js, unique-id.js, widgets/resizable.js, widgets/autocomplete.js, widgets/menu.js, widgets/mouse.js
|
||||
* Copyright jQuery Foundation and other contributors; Licensed MIT */
|
||||
@ -17,11 +17,11 @@
|
||||
|
||||
$.ui = $.ui || {};
|
||||
|
||||
var version = $.ui.version = "1.12.1";
|
||||
var version = $.ui.version = "1.13.1";
|
||||
|
||||
|
||||
/*!
|
||||
* jQuery UI Widget 1.12.1
|
||||
* jQuery UI Widget 1.13.0
|
||||
* http://jqueryui.com
|
||||
*
|
||||
* Copyright jQuery Foundation and other contributors
|
||||
@ -744,7 +744,7 @@ var widget = $.widget;
|
||||
|
||||
|
||||
/*!
|
||||
* jQuery UI Position 1.12.1
|
||||
* jQuery UI Position 1.13.1
|
||||
* http://jqueryui.com
|
||||
*
|
||||
* Copyright jQuery Foundation and other contributors
|
||||
@ -1232,7 +1232,7 @@ var position = $.ui.position;
|
||||
|
||||
|
||||
/*!
|
||||
* jQuery UI Disable Selection 1.12.1
|
||||
* jQuery UI Disable Selection 1.13.0
|
||||
* http://jqueryui.com
|
||||
*
|
||||
* Copyright jQuery Foundation and other contributors
|
||||
@ -1268,7 +1268,7 @@ var disableSelection = $.fn.extend( {
|
||||
|
||||
|
||||
/*!
|
||||
* jQuery UI Keycode 1.12.1
|
||||
* jQuery UI Keycode 1.13.0
|
||||
* http://jqueryui.com
|
||||
*
|
||||
* Copyright jQuery Foundation and other contributors
|
||||
@ -1303,7 +1303,7 @@ var keycode = $.ui.keyCode = {
|
||||
|
||||
|
||||
/*!
|
||||
* jQuery UI Unique ID 1.12.1
|
||||
* jQuery UI Unique ID 1.13.0
|
||||
* http://jqueryui.com
|
||||
*
|
||||
* Copyright jQuery Foundation and other contributors
|
||||
@ -1347,7 +1347,7 @@ var uniqueId = $.fn.extend( {
|
||||
var ie = $.ui.ie = !!/msie [\w.]+/.exec( navigator.userAgent.toLowerCase() );
|
||||
|
||||
/*!
|
||||
* jQuery UI Mouse 1.12.1
|
||||
* jQuery UI Mouse 1.13.0
|
||||
* http://jqueryui.com
|
||||
*
|
||||
* Copyright jQuery Foundation and other contributors
|
||||
@ -1368,7 +1368,7 @@ $( document ).on( "mouseup", function() {
|
||||
} );
|
||||
|
||||
var widgetsMouse = $.widget( "ui.mouse", {
|
||||
version: "1.12.1",
|
||||
version: "1.13.0",
|
||||
options: {
|
||||
cancel: "input, textarea, button, select, option",
|
||||
distance: 1,
|
||||
@ -1592,7 +1592,7 @@ var plugin = $.ui.plugin = {
|
||||
|
||||
|
||||
/*!
|
||||
* jQuery UI Resizable 1.12.1
|
||||
* jQuery UI Resizable 1.13.0
|
||||
* http://jqueryui.com
|
||||
*
|
||||
* Copyright jQuery Foundation and other contributors
|
||||
@ -1612,7 +1612,7 @@ var plugin = $.ui.plugin = {
|
||||
|
||||
|
||||
$.widget( "ui.resizable", $.ui.mouse, {
|
||||
version: "1.12.1",
|
||||
version: "1.13.0",
|
||||
widgetEventPrefix: "resize",
|
||||
options: {
|
||||
alsoResize: false,
|
||||
@ -2806,7 +2806,7 @@ var safeActiveElement = $.ui.safeActiveElement = function( document ) {
|
||||
|
||||
|
||||
/*!
|
||||
* jQuery UI Menu 1.12.1
|
||||
* jQuery UI Menu 1.13.0
|
||||
* http://jqueryui.com
|
||||
*
|
||||
* Copyright jQuery Foundation and other contributors
|
||||
@ -2826,7 +2826,7 @@ var safeActiveElement = $.ui.safeActiveElement = function( document ) {
|
||||
|
||||
|
||||
var widgetsMenu = $.widget( "ui.menu", {
|
||||
version: "1.12.1",
|
||||
version: "1.13.0",
|
||||
defaultElement: "<ul>",
|
||||
delay: 300,
|
||||
options: {
|
||||
@ -3461,7 +3461,7 @@ var widgetsMenu = $.widget( "ui.menu", {
|
||||
|
||||
|
||||
/*!
|
||||
* jQuery UI Autocomplete 1.12.1
|
||||
* jQuery UI Autocomplete 1.13.0
|
||||
* http://jqueryui.com
|
||||
*
|
||||
* Copyright jQuery Foundation and other contributors
|
||||
@ -3481,7 +3481,7 @@ var widgetsMenu = $.widget( "ui.menu", {
|
||||
|
||||
|
||||
$.widget( "ui.autocomplete", {
|
||||
version: "1.12.1",
|
||||
version: "1.13.0",
|
||||
defaultElement: "<input>",
|
||||
options: {
|
||||
appendTo: null,
|
||||
|
File diff suppressed because one or more lines are too long
@ -2,7 +2,7 @@
|
||||
"name": "jquery-ui",
|
||||
"title": "jQuery UI",
|
||||
"description": "A curated set of user interface interactions, effects, widgets, and themes built on top of the jQuery JavaScript Library.",
|
||||
"version": "1.12.1",
|
||||
"version": "1.13.0",
|
||||
"homepage": "http://jqueryui.com",
|
||||
"author": {
|
||||
"name": "jQuery Foundation and other contributors",
|
||||
|
@ -255,6 +255,9 @@ class StockHistoryCode(StatusCode):
|
||||
# Stock merging operations
|
||||
MERGED_STOCK_ITEMS = 45
|
||||
|
||||
# Convert stock item to variant
|
||||
CONVERTED_TO_VARIANT = 48
|
||||
|
||||
# Build order codes
|
||||
BUILD_OUTPUT_CREATED = 50
|
||||
BUILD_OUTPUT_COMPLETED = 55
|
||||
@ -294,6 +297,8 @@ class StockHistoryCode(StatusCode):
|
||||
|
||||
MERGED_STOCK_ITEMS: _('Merged stock items'),
|
||||
|
||||
CONVERTED_TO_VARIANT: _('Converted to variant'),
|
||||
|
||||
SENT_TO_CUSTOMER: _('Sent to customer'),
|
||||
RETURNED_FROM_CUSTOMER: _('Returned from customer'),
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
""" Version information for InvenTree.
|
||||
"""
|
||||
Version information for InvenTree.
|
||||
Provides information on the current InvenTree version
|
||||
"""
|
||||
|
||||
@ -8,150 +9,11 @@ import re
|
||||
|
||||
import common.models
|
||||
|
||||
from InvenTree.api_version import INVENTREE_API_VERSION
|
||||
|
||||
# InvenTree software version
|
||||
INVENTREE_SW_VERSION = "0.7.0 dev"
|
||||
|
||||
# InvenTree API version
|
||||
INVENTREE_API_VERSION = 39
|
||||
|
||||
"""
|
||||
Increment this API version number whenever there is a significant change to the API that any clients need to know about
|
||||
|
||||
v39 -> 2022-04-15 : https://github.com/inventree/InvenTree/pull/2833
|
||||
- Adds 'available_variant_stock' information to the BomItem API
|
||||
|
||||
v38 -> 2022-04-14 : https://github.com/inventree/InvenTree/pull/2828
|
||||
- Adds the ability to include stock test results for "installed items"
|
||||
|
||||
v37 -> 2022-04-07 : https://github.com/inventree/InvenTree/pull/2806
|
||||
- Adds extra stock availability information to the BomItem serializer
|
||||
|
||||
v36 -> 2022-04-03
|
||||
- Adds ability to filter part list endpoint by unallocated_stock argument
|
||||
|
||||
v35 -> 2022-04-01 : https://github.com/inventree/InvenTree/pull/2797
|
||||
- Adds stock allocation information to the Part API
|
||||
- Adds calculated field for "unallocated_quantity"
|
||||
|
||||
v34 -> 2022-03-25
|
||||
- Change permissions for "plugin list" API endpoint (now allows any authenticated user)
|
||||
|
||||
v33 -> 2022-03-24
|
||||
- Adds "plugins_enabled" information to root API endpoint
|
||||
|
||||
v32 -> 2022-03-19
|
||||
- Adds "parameters" detail to Part API endpoint (use ¶meters=true)
|
||||
- Adds ability to filter PartParameterTemplate API by Part instance
|
||||
- Adds ability to filter PartParameterTemplate API by PartCategory instance
|
||||
|
||||
v31 -> 2022-03-14
|
||||
- Adds "updated" field to SupplierPriceBreakList and SupplierPriceBreakDetail API endpoints
|
||||
|
||||
v30 -> 2022-03-09
|
||||
- Adds "exclude_location" field to BuildAutoAllocation API endpoint
|
||||
- Allows BuildItem API endpoint to be filtered by BomItem relation
|
||||
|
||||
v29 -> 2022-03-08
|
||||
- Adds "scheduling" endpoint for predicted stock scheduling information
|
||||
|
||||
v28 -> 2022-03-04
|
||||
- Adds an API endpoint for auto allocation of stock items against a build order
|
||||
- Ref: https://github.com/inventree/InvenTree/pull/2713
|
||||
|
||||
v27 -> 2022-02-28
|
||||
- Adds target_date field to individual line items for purchase orders and sales orders
|
||||
|
||||
v26 -> 2022-02-17
|
||||
- Adds API endpoint for uploading a BOM file and extracting data
|
||||
|
||||
v25 -> 2022-02-17
|
||||
- Adds ability to filter "part" list endpoint by "in_bom_for" argument
|
||||
|
||||
v24 -> 2022-02-10
|
||||
- Adds API endpoint for deleting (cancelling) build order outputs
|
||||
|
||||
v23 -> 2022-02-02
|
||||
- Adds API endpoints for managing plugin classes
|
||||
- Adds API endpoints for managing plugin settings
|
||||
|
||||
v22 -> 2021-12-20
|
||||
- Adds API endpoint to "merge" multiple stock items
|
||||
|
||||
v21 -> 2021-12-04
|
||||
- Adds support for multiple "Shipments" against a SalesOrder
|
||||
- Refactors process for stock allocation against a SalesOrder
|
||||
|
||||
v20 -> 2021-12-03
|
||||
- Adds ability to filter POLineItem endpoint by "base_part"
|
||||
- Adds optional "order_detail" to POLineItem list endpoint
|
||||
|
||||
v19 -> 2021-12-02
|
||||
- Adds the ability to filter the StockItem API by "part_tree"
|
||||
- Returns only stock items which match a particular part.tree_id field
|
||||
|
||||
v18 -> 2021-11-15
|
||||
- Adds the ability to filter BomItem API by "uses" field
|
||||
- This returns a list of all BomItems which "use" the specified part
|
||||
- Includes inherited BomItem objects
|
||||
|
||||
v17 -> 2021-11-09
|
||||
- Adds API endpoints for GLOBAL and USER settings objects
|
||||
- Ref: https://github.com/inventree/InvenTree/pull/2275
|
||||
|
||||
v16 -> 2021-10-17
|
||||
- Adds API endpoint for completing build order outputs
|
||||
|
||||
v15 -> 2021-10-06
|
||||
- Adds detail endpoint for SalesOrderAllocation model
|
||||
- Allows use of the API forms interface for adjusting SalesOrderAllocation objects
|
||||
|
||||
v14 -> 2021-10-05
|
||||
- Stock adjustment actions API is improved, using native DRF serializer support
|
||||
- However adjustment actions now only support 'pk' as a lookup field
|
||||
|
||||
v13 -> 2021-10-05
|
||||
- Adds API endpoint to allocate stock items against a BuildOrder
|
||||
- Updates StockItem API with improved filtering against BomItem data
|
||||
|
||||
v12 -> 2021-09-07
|
||||
- Adds API endpoint to receive stock items against a PurchaseOrder
|
||||
|
||||
v11 -> 2021-08-26
|
||||
- Adds "units" field to PartBriefSerializer
|
||||
- This allows units to be introspected from the "part_detail" field in the StockItem serializer
|
||||
|
||||
v10 -> 2021-08-23
|
||||
- Adds "purchase_price_currency" to StockItem serializer
|
||||
- Adds "purchase_price_string" to StockItem serializer
|
||||
- Purchase price is now writable for StockItem serializer
|
||||
|
||||
v9 -> 2021-08-09
|
||||
- Adds "price_string" to part pricing serializers
|
||||
|
||||
v8 -> 2021-07-19
|
||||
- Refactors the API interface for SupplierPart and ManufacturerPart models
|
||||
- ManufacturerPart objects can no longer be created via the SupplierPart API endpoint
|
||||
|
||||
v7 -> 2021-07-03
|
||||
- Introduced the concept of "API forms" in https://github.com/inventree/InvenTree/pull/1716
|
||||
- API OPTIONS endpoints provide comprehensive field metedata
|
||||
- Multiple new API endpoints added for database models
|
||||
|
||||
v6 -> 2021-06-23
|
||||
- Part and Company images can now be directly uploaded via the REST API
|
||||
|
||||
v5 -> 2021-06-21
|
||||
- Adds API interface for manufacturer part parameters
|
||||
|
||||
v4 -> 2021-06-01
|
||||
- BOM items can now accept "variant stock" to be assigned against them
|
||||
- Many slight API tweaks were needed to get this to work properly!
|
||||
|
||||
v3 -> 2021-05-22:
|
||||
- The updated StockItem "history tracking" now uses a different interface
|
||||
|
||||
"""
|
||||
|
||||
|
||||
def inventreeInstanceName():
|
||||
""" Returns the InstanceName settings for the current database """
|
||||
|
@ -238,7 +238,7 @@
|
||||
});
|
||||
|
||||
{% if company.is_customer %}
|
||||
onPanelLoad('panel-sales-orders', function() {
|
||||
onPanelLoad('sales-orders', function() {
|
||||
loadSalesOrderTable("#sales-order-table", {
|
||||
url: "{% url 'api-so-list' %}",
|
||||
params: {
|
||||
|
BIN
InvenTree/locale/cs/LC_MESSAGES/django.mo
Normal file
BIN
InvenTree/locale/cs/LC_MESSAGES/django.mo
Normal file
Binary file not shown.
10114
InvenTree/locale/cs/LC_MESSAGES/django.po
Normal file
10114
InvenTree/locale/cs/LC_MESSAGES/django.po
Normal file
File diff suppressed because it is too large
Load Diff
BIN
InvenTree/locale/fa/LC_MESSAGES/django.mo
Normal file
BIN
InvenTree/locale/fa/LC_MESSAGES/django.mo
Normal file
Binary file not shown.
7845
InvenTree/locale/fa/LC_MESSAGES/django.po
Normal file
7845
InvenTree/locale/fa/LC_MESSAGES/django.po
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,10 +0,0 @@
|
||||
{% load i18n %}
|
||||
|
||||
<div class="markdownx row">
|
||||
<div class="markdown col-md-6">
|
||||
{% include 'django/forms/widgets/textarea.html' %}
|
||||
</div>
|
||||
<div class="markdown col-md-6">
|
||||
<div class="markdownx-preview"></div>
|
||||
</div>
|
||||
</div>
|
@ -187,6 +187,15 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class='panel panel-hidden' id='panel-stock'>
|
||||
<div class='panel-heading'>
|
||||
<h4>{% trans "Stock Items" %}</h4>
|
||||
</div>
|
||||
<div class='panel-content'>
|
||||
{% include "stock_table.html" %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class='panel panel-hidden' id='panel-parameters'>
|
||||
<div class='panel-heading'>
|
||||
<h4>{% trans "Part Parameters" %}</h4>
|
||||
@ -223,6 +232,21 @@
|
||||
{{ block.super }}
|
||||
|
||||
{% if category %}
|
||||
|
||||
onPanelLoad('stock', function() {
|
||||
loadStockTable(
|
||||
$('#stock-table'),
|
||||
{
|
||||
params: {
|
||||
category: {{ category.pk }},
|
||||
part_detail: true,
|
||||
location_detail: true,
|
||||
supplier_part_detail: true,
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
onPanelLoad('parameters', function() {
|
||||
loadParametricPartTable(
|
||||
"#parametric-part-table",
|
||||
|
@ -14,6 +14,8 @@
|
||||
{% include "sidebar_link.html" with url=url text=text icon="fa-file-upload" %}
|
||||
{% endif %}
|
||||
{% if category %}
|
||||
{% trans "Stock Items" as text %}
|
||||
{% include "sidebar_item.html" with label='stock' text=text icon='fa-boxes' %}
|
||||
{% trans "Parameters" as text %}
|
||||
{% include "sidebar_item.html" with label="parameters" text=text icon="fa-tasks" %}
|
||||
{% endif %}
|
@ -94,6 +94,14 @@ class IntegrationPluginBase(MixinBase, plugin_base.InvenTreePluginBase):
|
||||
"""
|
||||
return getattr(self, 'is_package', False)
|
||||
|
||||
@property
|
||||
def is_sample(self):
|
||||
"""
|
||||
Is this plugin part of the samples?
|
||||
"""
|
||||
path = str(self.package_path)
|
||||
return path.startswith('plugin/samples/')
|
||||
|
||||
# region properties
|
||||
@property
|
||||
def slug(self):
|
||||
|
@ -402,11 +402,51 @@ class StockFilter(rest_filters.FilterSet):
|
||||
serialized = rest_filters.BooleanFilter(label='Has serial number', method='filter_serialized')
|
||||
|
||||
def filter_serialized(self, queryset, name, value):
|
||||
"""
|
||||
Filter by whether the StockItem has a serial number (or not)
|
||||
"""
|
||||
|
||||
q = Q(serial=None) | Q(serial='')
|
||||
|
||||
if str2bool(value):
|
||||
queryset = queryset.exclude(serial=None)
|
||||
queryset = queryset.exclude(q)
|
||||
else:
|
||||
queryset = queryset.filter(serial=None)
|
||||
queryset = queryset.filter(q)
|
||||
|
||||
return queryset
|
||||
|
||||
has_batch = rest_filters.BooleanFilter(label='Has batch code', method='filter_has_batch')
|
||||
|
||||
def filter_has_batch(self, queryset, name, value):
|
||||
"""
|
||||
Filter by whether the StockItem has a batch code (or not)
|
||||
"""
|
||||
|
||||
q = Q(batch=None) | Q(batch='')
|
||||
|
||||
if str2bool(value):
|
||||
queryset = queryset.exclude(q)
|
||||
else:
|
||||
queryset = queryset.filter(q)
|
||||
|
||||
return queryset
|
||||
|
||||
tracked = rest_filters.BooleanFilter(label='Tracked', method='filter_tracked')
|
||||
|
||||
def filter_tracked(self, queryset, name, value):
|
||||
"""
|
||||
Filter by whether this stock item is *tracked*, meaning either:
|
||||
- It has a serial number
|
||||
- It has a batch code
|
||||
"""
|
||||
|
||||
q_batch = Q(batch=None) | Q(batch='')
|
||||
q_serial = Q(serial=None) | Q(serial='')
|
||||
|
||||
if str2bool(value):
|
||||
queryset = queryset.exclude(q_batch & q_serial)
|
||||
else:
|
||||
queryset = queryset.filter(q_batch & q_serial)
|
||||
|
||||
return queryset
|
||||
|
||||
@ -1220,6 +1260,15 @@ class StockTrackingList(generics.ListAPIView):
|
||||
if not deltas:
|
||||
deltas = {}
|
||||
|
||||
# Add part detail
|
||||
if 'part' in deltas:
|
||||
try:
|
||||
part = Part.objects.get(pk=deltas['part'])
|
||||
serializer = PartBriefSerializer(part)
|
||||
deltas['part_detail'] = serializer.data
|
||||
except:
|
||||
pass
|
||||
|
||||
# Add location detail
|
||||
if 'location' in deltas:
|
||||
try:
|
||||
|
@ -453,6 +453,12 @@ class StockItem(MPTTModel):
|
||||
|
||||
super().clean()
|
||||
|
||||
if self.serial is not None and type(self.serial) is str:
|
||||
self.serial = self.serial.strip()
|
||||
|
||||
if self.batch is not None and type(self.batch) is str:
|
||||
self.batch = self.batch.strip()
|
||||
|
||||
try:
|
||||
if self.part.trackable:
|
||||
# Trackable parts must have integer values for quantity field!
|
||||
@ -718,6 +724,33 @@ class StockItem(MPTTModel):
|
||||
help_text=_('Select Owner'),
|
||||
related_name='stock_items')
|
||||
|
||||
@transaction.atomic
|
||||
def convert_to_variant(self, variant, user, notes=None):
|
||||
"""
|
||||
Convert this StockItem instance to a "variant",
|
||||
i.e. change the "part" reference field
|
||||
"""
|
||||
|
||||
if not variant:
|
||||
# Ignore null values
|
||||
return
|
||||
|
||||
if variant == self.part:
|
||||
# Variant is the same as the current part
|
||||
return
|
||||
|
||||
self.part = variant
|
||||
self.save()
|
||||
|
||||
self.add_tracking_entry(
|
||||
StockHistoryCode.CONVERTED_TO_VARIANT,
|
||||
user,
|
||||
deltas={
|
||||
'part': variant.pk,
|
||||
},
|
||||
notes=_('Converted to part') + ': ' + variant.full_name,
|
||||
)
|
||||
|
||||
def get_item_owner(self):
|
||||
"""
|
||||
Return the closest "owner" for this StockItem.
|
||||
|
@ -26,11 +26,12 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class='panel-content'>
|
||||
<div id='table-toolbar'>
|
||||
<div id='tracking-table-toolbar'>
|
||||
<div class='btn-group'>
|
||||
{% include "filter_list.html" with id="stocktracking" %}
|
||||
</div>
|
||||
</div>
|
||||
<table class='table table-condensed table-striped' id='track-table' data-toolbar='#table-toolbar'>
|
||||
<table class='table table-condensed table-striped' id='track-table' data-toolbar='#tracking-table-toolbar'>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
@ -342,7 +343,6 @@
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
loadStockTrackingTable($("#track-table"), {
|
||||
params: {
|
||||
ordering: '-date',
|
||||
|
@ -210,6 +210,46 @@ class StockItemListTest(StockAPITestCase):
|
||||
for item in response:
|
||||
self.assertIsNone(item['serial'])
|
||||
|
||||
def test_filter_by_has_batch(self):
|
||||
"""
|
||||
Test the 'has_batch' filter, which tests if the stock item has been assigned a batch code
|
||||
"""
|
||||
|
||||
with_batch = self.get_stock(has_batch=1)
|
||||
without_batch = self.get_stock(has_batch=0)
|
||||
|
||||
n_stock_items = StockItem.objects.all().count()
|
||||
|
||||
# Total sum should equal the total count of stock items
|
||||
self.assertEqual(n_stock_items, len(with_batch) + len(without_batch))
|
||||
|
||||
for item in with_batch:
|
||||
self.assertFalse(item['batch'] in [None, ''])
|
||||
|
||||
for item in without_batch:
|
||||
self.assertTrue(item['batch'] in [None, ''])
|
||||
|
||||
def test_filter_by_tracked(self):
|
||||
"""
|
||||
Test the 'tracked' filter.
|
||||
This checks if the stock item has either a batch code *or* a serial number
|
||||
"""
|
||||
|
||||
tracked = self.get_stock(tracked=True)
|
||||
untracked = self.get_stock(tracked=False)
|
||||
|
||||
n_stock_items = StockItem.objects.all().count()
|
||||
|
||||
self.assertEqual(n_stock_items, len(tracked) + len(untracked))
|
||||
|
||||
blank = [None, '']
|
||||
|
||||
for item in tracked:
|
||||
self.assertTrue(item['batch'] not in blank or item['serial'] not in blank)
|
||||
|
||||
for item in untracked:
|
||||
self.assertTrue(item['batch'] in blank and item['serial'] in blank)
|
||||
|
||||
def test_filter_by_expired(self):
|
||||
"""
|
||||
Filter StockItem by expiry status
|
||||
|
@ -644,6 +644,16 @@ class StockItemConvert(AjaxUpdateView):
|
||||
|
||||
return form
|
||||
|
||||
def save(self, obj, form):
|
||||
|
||||
stock_item = self.get_object()
|
||||
|
||||
variant = form.cleaned_data.get('part', None)
|
||||
|
||||
stock_item.convert_to_variant(variant, user=self.request.user)
|
||||
|
||||
return stock_item
|
||||
|
||||
|
||||
class StockLocationCreate(AjaxCreateView):
|
||||
"""
|
||||
|
@ -77,6 +77,12 @@
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
{% if plugin.is_sample %}
|
||||
<a class='sidebar-selector' id='select-plugin-{{plugin_key}}' data-bs-parent="#sidebar">
|
||||
<span class='badge bg-info rounded-pill'>{% trans "code sample" %}</span>
|
||||
</a>
|
||||
{% endif %}
|
||||
|
||||
{% if plugin.website %}
|
||||
<a href="{{ plugin.website }}"><span class="fas fa-globe"></span></a>
|
||||
{% endif %}
|
||||
|
@ -99,14 +99,22 @@ function renderStockItem(name, data, parameters={}, options={}) {
|
||||
|
||||
var stock_detail = '';
|
||||
|
||||
if (data.serial && data.quantity == 1) {
|
||||
stock_detail = `{% trans "Serial Number" %}: ${data.serial}`;
|
||||
} else if (data.quantity == 0) {
|
||||
if (data.quantity == 0) {
|
||||
stock_detail = `<span class='badge rounded-pill bg-danger'>{% trans "No Stock"% }</span>`;
|
||||
} else {
|
||||
stock_detail = `{% trans "Quantity" %}: ${data.quantity}`;
|
||||
if (data.serial && data.quantity == 1) {
|
||||
stock_detail = `{% trans "Serial Number" %}: ${data.serial}`;
|
||||
} else {
|
||||
stock_detail = `{% trans "Quantity" %}: ${data.quantity}`;
|
||||
}
|
||||
|
||||
if (data.batch) {
|
||||
stock_detail += ` - <small>{% trans "Batch" %}: ${data.batch}</small>`;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
var html = `
|
||||
<span>
|
||||
${part_detail}
|
||||
|
@ -171,6 +171,9 @@ function notificationCheck(force = false) {
|
||||
{
|
||||
success: function(response) {
|
||||
updateNotificationIndicator(response.length);
|
||||
},
|
||||
error: function(xhr) {
|
||||
console.warn('Could not access server: /api/notifications');
|
||||
}
|
||||
}
|
||||
);
|
||||
|
@ -293,6 +293,7 @@ function categoryFields() {
|
||||
return {
|
||||
parent: {
|
||||
help_text: '{% trans "Parent part category" %}',
|
||||
required: false,
|
||||
},
|
||||
name: {},
|
||||
description: {},
|
||||
|
@ -107,6 +107,7 @@ function stockLocationFields(options={}) {
|
||||
var fields = {
|
||||
parent: {
|
||||
help_text: '{% trans "Parent stock location" %}',
|
||||
required: false,
|
||||
},
|
||||
name: {},
|
||||
description: {},
|
||||
@ -240,9 +241,11 @@ function stockItemFields(options={}) {
|
||||
serial: {
|
||||
icon: 'fa-hashtag',
|
||||
},
|
||||
batch: {
|
||||
icon: 'fa-layer-group',
|
||||
},
|
||||
status: {},
|
||||
expiry_date: {},
|
||||
batch: {},
|
||||
purchase_price: {
|
||||
icon: 'fa-dollar-sign',
|
||||
},
|
||||
@ -963,6 +966,10 @@ function adjustStock(action, items, options={}) {
|
||||
quantity = `#${item.serial}`;
|
||||
}
|
||||
|
||||
if (item.batch) {
|
||||
quantity += ` - <small>{% trans "Batch" %}: ${item.batch}</small>`;
|
||||
}
|
||||
|
||||
var actionInput = '';
|
||||
|
||||
if (actionTitle != null) {
|
||||
@ -2314,6 +2321,23 @@ function loadStockTrackingTable(table, options) {
|
||||
|
||||
var cols = [];
|
||||
|
||||
var filterTarget = '#filter-list-stocktracking';
|
||||
|
||||
var filterKey = 'stocktracking';
|
||||
|
||||
var filters = loadTableFilters(filterKey);
|
||||
|
||||
var params = options.params;
|
||||
|
||||
var original = {};
|
||||
|
||||
for (var k in params) {
|
||||
original[k] = params[k];
|
||||
filters[k] = params[k];
|
||||
}
|
||||
|
||||
setupFilterList(filterKey, table, filterTarget);
|
||||
|
||||
// Date
|
||||
cols.push({
|
||||
field: 'date',
|
||||
@ -2351,6 +2375,19 @@ function loadStockTrackingTable(table, options) {
|
||||
return html;
|
||||
}
|
||||
|
||||
// Part information
|
||||
if (details.part) {
|
||||
html += `<tr><th>{% trans "Part" %}</th><td>`;
|
||||
|
||||
if (details.part_detail) {
|
||||
html += renderLink(details.part_detail.full_name, `/part/${details.part}/`);
|
||||
} else {
|
||||
html += `{% trans "Part information unavailable" %}`;
|
||||
}
|
||||
|
||||
html += `</td></tr>`;
|
||||
}
|
||||
|
||||
// Location information
|
||||
if (details.location) {
|
||||
|
||||
@ -2488,27 +2525,10 @@ function loadStockTrackingTable(table, options) {
|
||||
}
|
||||
});
|
||||
|
||||
/*
|
||||
// 2021-05-11 - Ability to edit or delete StockItemTracking entries is now removed
|
||||
cols.push({
|
||||
sortable: false,
|
||||
formatter: function(value, row, index, field) {
|
||||
// Manually created entries can be edited or deleted
|
||||
if (false && !row.system) {
|
||||
var bEdit = "<button title='{% trans 'Edit tracking entry' %}' class='btn btn-entry-edit btn-outline-secondary' type='button' url='/stock/track/" + row.pk + "/edit/'><span class='fas fa-edit'/></button>";
|
||||
var bDel = "<button title='{% trans 'Delete tracking entry' %}' class='btn btn-entry-delete btn-outline-secondary' type='button' url='/stock/track/" + row.pk + "/delete/'><span class='fas fa-trash-alt icon-red'/></button>";
|
||||
|
||||
return "<div class='btn-group' role='group'>" + bEdit + bDel + "</div>";
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
});
|
||||
*/
|
||||
|
||||
table.inventreeTable({
|
||||
method: 'get',
|
||||
queryParams: options.params,
|
||||
queryParams: filters,
|
||||
original: original,
|
||||
columns: cols,
|
||||
url: options.url,
|
||||
});
|
||||
@ -2639,7 +2659,8 @@ function installStockItem(stock_item_id, part_id, options={}) {
|
||||
<ul>
|
||||
<li>{% trans "The Stock Item links to a Part which is the BOM for this Stock Item" %}</li>
|
||||
<li>{% trans "The Stock Item is currently available in stock" %}</li>
|
||||
<li>{% trans "The Stock Item is serialized and does not belong to another item" %}</li>
|
||||
<li>{% trans "The Stock Item is not already installed in another item" %}</li>
|
||||
<li>{% trans "The Stock Item is tracked by either a batch code or serial number" %}</li>
|
||||
</ul>
|
||||
</div>`;
|
||||
|
||||
@ -2665,7 +2686,7 @@ function installStockItem(stock_item_id, part_id, options={}) {
|
||||
filters: {
|
||||
part_detail: true,
|
||||
in_stock: true,
|
||||
serialized: true,
|
||||
tracked: true,
|
||||
},
|
||||
adjustFilters: function(filters, opts) {
|
||||
var part = getFormFieldValue('part', {}, opts);
|
||||
|
@ -234,10 +234,19 @@ function getAvailableTableFilters(tableKey) {
|
||||
title: '{% trans "Stock status" %}',
|
||||
description: '{% trans "Stock status" %}',
|
||||
},
|
||||
has_batch: {
|
||||
title: '{% trans "Has batch code" %}',
|
||||
type: 'bool',
|
||||
},
|
||||
batch: {
|
||||
title: '{% trans "Batch" %}',
|
||||
description: '{% trans "Batch code" %}',
|
||||
},
|
||||
tracked: {
|
||||
title: '{% trans "Tracked" %}',
|
||||
description: '{% trans "Stock item is tracked by either batch code or serial number" %}',
|
||||
type: 'bool',
|
||||
},
|
||||
has_purchase_price: {
|
||||
type: 'bool',
|
||||
title: '{% trans "Has purchase price" %}',
|
||||
|
Reference in New Issue
Block a user