diff --git a/InvenTree/part/forms.py b/InvenTree/part/forms.py index 2eb9600065..6430ac922b 100644 --- a/InvenTree/part/forms.py +++ b/InvenTree/part/forms.py @@ -101,11 +101,6 @@ class EditPartForm(HelperForm): 'default_supplier', 'units', 'minimum_stock', - 'assembly', - 'component', - 'trackable', - 'purchaseable', - 'salable', 'notes', ] diff --git a/InvenTree/part/migrations/0009_part_virtual.py b/InvenTree/part/migrations/0009_part_virtual.py new file mode 100644 index 0000000000..8a934e9064 --- /dev/null +++ b/InvenTree/part/migrations/0009_part_virtual.py @@ -0,0 +1,18 @@ +# Generated by Django 2.2.2 on 2019-06-18 08:33 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('part', '0008_auto_20190618_0042'), + ] + + operations = [ + migrations.AddField( + model_name='part', + name='virtual', + field=models.BooleanField(default=False, help_text='Is this a virtual part, such as a software product or license?'), + ), + ] diff --git a/InvenTree/part/models.py b/InvenTree/part/models.py index 7d5476db5d..92acce5026 100644 --- a/InvenTree/part/models.py +++ b/InvenTree/part/models.py @@ -216,6 +216,7 @@ class Part(models.Model): purchaseable: Can this part be purchased from suppliers? trackable: Trackable parts can have unique serial numbers assigned, etc, etc active: Is this part active? Parts are deactivated instead of being deleted + virtual: Is this part "virtual"? e.g. a software product or similar notes: Additional notes field for this part """ @@ -377,6 +378,8 @@ class Part(models.Model): active = models.BooleanField(default=True, help_text='Is this part active?') + virtual = models.BooleanField(default=False, help_text='Is this a virtual part, such as a software product or license?') + notes = models.TextField(blank=True) bom_checksum = models.CharField(max_length=128, blank=True, help_text='Stored BOM checksum') diff --git a/InvenTree/part/serializers.py b/InvenTree/part/serializers.py index 36be5de6db..eaea7ecebc 100644 --- a/InvenTree/part/serializers.py +++ b/InvenTree/part/serializers.py @@ -100,8 +100,10 @@ class PartSerializer(InvenTreeModelSerializer): 'assembly', 'component', 'trackable', + 'purchaseable', 'salable', 'active', + 'virtual', ] diff --git a/InvenTree/part/templates/part/detail.html b/InvenTree/part/templates/part/detail.html index fe357a6bdc..fe07954a5a 100644 --- a/InvenTree/part/templates/part/detail.html +++ b/InvenTree/part/templates/part/detail.html @@ -6,7 +6,6 @@
-

Part Details

@@ -30,10 +29,9 @@
-
-
+

Part Details

@@ -102,37 +100,62 @@
Part name
+

Part Type

- {% if part.assembly %} - - + + + {% if part.virtual %} + + {% else %} + + {% endif %} + + + + + {% if part.assembly %} + + {% else %} + + {% endif %} - {% endif %} - {% if part.component %} - + + {% if part.component %} + + {% else %} + + {% endif %} - {% endif %} - {% if part.trackable %} - + + {% if part.trackable %} + + {% else %} + + {% endif %} - {% endif %} - {% if part.purchaseable %} - + + {% if part.purchaseable %} + + {% else %} + + {% endif %} - {% endif %} - {% if part.salable %} - - + + + {% if part.salable %} + + {% else %} + + {% endif %} - {% endif %}
AssemblyThis part can be assembled from other partsVirtual{% include "slide.html" with state=part.virtual field='virtual' %}Part is virtual (not a physical part)Part is not a virtual part
Assembly{% include "slide.html" with state=part.assembly field='assembly' %}Part can be assembled from other partsPart cannot be assembled from other parts
ComponentThis part can be used in assemblies{% include "slide.html" with state=part.component field='component' %}Part can be used in assembliesPart cannot be used in assemblies
TrackableStock for this part will be tracked by (serial or batch){% include "slide.html" with state=part.trackable field='trackable' %}Part stock will be tracked by (serial or batch)Part stock will not be tracked by
PurchaseableThis part can be purchased from external suppliers{% include "slide.html" with state=part.purchaseable field='purchaseable' %}Part can be purchased from external suppliersPart can be purchased from external suppliers
SalableThis part can be sold to customersSellable{% include "slide.html" with state=part.salable field='salable' %}Part can be sold to customersPart cannot be sold to customers
@@ -152,6 +175,25 @@ {% block js_ready %} {{ block.super }} + + $(".slidey").change(function() { + var field = $(this).attr('field'); + + var checked = $(this).prop('checked'); + + var data = {}; + + data[field] = checked; + + // Update the particular field + inventreePut("/api/part/{{ part.id }}/", + data, + { + method: 'PATCH', + reloadOnSuccess: true, + }, + ); + }); $("#duplicate-part").click(function() { launchModalForm( diff --git a/InvenTree/static/css/bootstrap-toggle.css b/InvenTree/static/css/bootstrap-toggle.css new file mode 100644 index 0000000000..c0e49e7254 --- /dev/null +++ b/InvenTree/static/css/bootstrap-toggle.css @@ -0,0 +1,83 @@ +/*! ======================================================================== + * Bootstrap Toggle: bootstrap-toggle.css v2.2.0 + * http://www.bootstraptoggle.com + * ======================================================================== + * Copyright 2014 Min Hur, The New York Times Company + * Licensed under MIT + * ======================================================================== */ + + +.checkbox label .toggle, +.checkbox-inline .toggle { + margin-left: -20px; + margin-right: 5px; +} + +.toggle { + position: relative; + overflow: hidden; +} +.toggle input[type="checkbox"] { + display: none; +} +.toggle-group { + position: absolute; + width: 200%; + top: 0; + bottom: 0; + left: 0; + transition: left 0.35s; + -webkit-transition: left 0.35s; + -moz-user-select: none; + -webkit-user-select: none; +} +.toggle.off .toggle-group { + left: -100%; +} +.toggle-on { + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 50%; + margin: 0; + border: 0; + border-radius: 0; +} +.toggle-off { + position: absolute; + top: 0; + bottom: 0; + left: 50%; + right: 0; + margin: 0; + border: 0; + border-radius: 0; +} +.toggle-handle { + position: relative; + margin: 0 auto; + padding-top: 0px; + padding-bottom: 0px; + height: 100%; + width: 0px; + border-width: 0 1px; +} + +.toggle.btn { min-width: 59px; min-height: 34px; } +.toggle-on.btn { padding-right: 24px; } +.toggle-off.btn { padding-left: 24px; } + +.toggle.btn-lg { min-width: 79px; min-height: 45px; } +.toggle-on.btn-lg { padding-right: 31px; } +.toggle-off.btn-lg { padding-left: 31px; } +.toggle-handle.btn-lg { width: 40px; } + +.toggle.btn-sm { border-radius: 15px; min-width: 50px; min-height: 20px; max-height: 25px;} +.toggle-on.btn-sm { padding-right: 20px; } +.toggle-off.btn-sm { padding-left: 20px; } + +.toggle.btn-xs { min-width: 35px; min-height: 22px;} +.toggle-on.btn-xs { padding-right: 12px; } +.toggle-off.btn-xs { padding-left: 12px; } + diff --git a/InvenTree/static/css/inventree.css b/InvenTree/static/css/inventree.css index 755b41c104..e4ebd182ee 100644 --- a/InvenTree/static/css/inventree.css +++ b/InvenTree/static/css/inventree.css @@ -22,6 +22,14 @@ color: rgb(13, 245, 25); } +.glyphicon-ok { + color: #5f5; +} + +.glyphicon-remove { + color: #f55; +} + /* CSS overrides for treeview */ .expand-icon { font-size: 11px; diff --git a/InvenTree/static/script/bootstrap/bootstrap-toggle.js b/InvenTree/static/script/bootstrap/bootstrap-toggle.js new file mode 100644 index 0000000000..3a670dd218 --- /dev/null +++ b/InvenTree/static/script/bootstrap/bootstrap-toggle.js @@ -0,0 +1,180 @@ +/*! ======================================================================== + * Bootstrap Toggle: bootstrap-toggle.js v2.2.0 + * http://www.bootstraptoggle.com + * ======================================================================== + * Copyright 2014 Min Hur, The New York Times Company + * Licensed under MIT + * ======================================================================== */ + + + +function ($) { + 'use strict'; + + // TOGGLE PUBLIC CLASS DEFINITION + // ============================== + + var Toggle = function (element, options) { + this.$element = $(element) + this.options = $.extend({}, this.defaults(), options) + this.render() + } + + Toggle.VERSION = '2.2.0' + + Toggle.DEFAULTS = { + on: '', + off: '', + onstyle: 'primary', + offstyle: 'default', + size: 'normal', + style: '', + width: null, + height: null + } + + Toggle.prototype.defaults = function() { + return { + on: this.$element.attr('data-on') || Toggle.DEFAULTS.on, + off: this.$element.attr('data-off') || Toggle.DEFAULTS.off, + onstyle: this.$element.attr('data-onstyle') || Toggle.DEFAULTS.onstyle, + offstyle: this.$element.attr('data-offstyle') || Toggle.DEFAULTS.offstyle, + size: this.$element.attr('data-size') || Toggle.DEFAULTS.size, + style: this.$element.attr('data-style') || Toggle.DEFAULTS.style, + width: this.$element.attr('data-width') || Toggle.DEFAULTS.width, + height: this.$element.attr('data-height') || Toggle.DEFAULTS.height + } + } + + Toggle.prototype.render = function () { + this._onstyle = 'btn-' + this.options.onstyle + this._offstyle = 'btn-' + this.options.offstyle + var size = this.options.size === 'large' ? 'btn-lg' + : this.options.size === 'small' ? 'btn-sm' + : this.options.size === 'mini' ? 'btn-xs' + : '' + var $toggleOn = $('