Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Build system updates #1063

Merged
merged 81 commits into from
Nov 3, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
81 commits
Select commit Hold shift + click to select a range
fdcef7b
Add "install_into" field for BuildItem
SchrodingersGat Oct 20, 2020
28460b3
Validate that the BuildItem quantity is an integer
SchrodingersGat Oct 20, 2020
ac79e13
Add "destination" field to BuildOrder
SchrodingersGat Oct 20, 2020
2df0f03
Change "ALLOCATED" to "PRODUCTION"
SchrodingersGat Oct 20, 2020
2e4613e
Updates to build forms / etc
SchrodingersGat Oct 20, 2020
652c2db
Automagically disable 'serial_numbers' field for StockItemCreate form
SchrodingersGat Oct 20, 2020
3bb247a
Create an initial stockitem output when a new build is created
SchrodingersGat Oct 20, 2020
fd6d630
Improve grouping in Stock table
SchrodingersGat Oct 20, 2020
e025360
Add a "completed" field to the Build model
SchrodingersGat Oct 20, 2020
8ae16a1
Build - Add functions to access build outputs
SchrodingersGat Oct 20, 2020
96277ed
Improvements to progress bar function
SchrodingersGat Oct 20, 2020
f989d3b
Change to using spinner icon
SchrodingersGat Oct 21, 2020
1ca08f8
Filter builditem API by 'output' stock item
SchrodingersGat Oct 22, 2020
fae516b
Add build output selection to builditem creation form
SchrodingersGat Oct 22, 2020
d37cdd8
Improved filtering for stockitems going into a buildallocation
SchrodingersGat Oct 22, 2020
ae20db0
Add actions for the sub-table allocation list
SchrodingersGat Oct 22, 2020
23ac83d
Change extension on "dynamic" js files
SchrodingersGat Oct 22, 2020
6245d65
Tweaks
SchrodingersGat Oct 22, 2020
33c454e
Add action buttons to each build output
SchrodingersGat Oct 22, 2020
f4f6253
Better table sorting for allocation quantity
SchrodingersGat Oct 22, 2020
5db043a
Launch modal dialog to auto-allocate against a specific build output
SchrodingersGat Oct 22, 2020
076d5c4
Cleanup get_required_parts function
SchrodingersGat Oct 23, 2020
0752df2
Bug fixes for BuildItemCreate view:
SchrodingersGat Oct 23, 2020
fb7d9a7
Move "getAvailableStockItems" to the build model
SchrodingersGat Oct 23, 2020
a71a51b
Build can be "unallocated" against a single build output
SchrodingersGat Oct 23, 2020
ea7b1b6
Delete a build output entirely
SchrodingersGat Oct 23, 2020
b45a11a
Refactor: Add "makeIconBadge" javascript function
SchrodingersGat Oct 23, 2020
b7e7543
Add some more buttons to build table
SchrodingersGat Oct 24, 2020
a3265ef
Unallocate stock against a particular line item
SchrodingersGat Oct 24, 2020
42c1210
Calculate required build quantity
SchrodingersGat Oct 24, 2020
c63a093
Hide some buttons if row is fully allocated already
SchrodingersGat Oct 24, 2020
767ceed
Update translation files
SchrodingersGat Oct 24, 2020
6aaf178
Check "trackable" status of part
SchrodingersGat Oct 25, 2020
ffe1576
Update validation "rules" for BuildItem
SchrodingersGat Oct 25, 2020
815d4bf
Add new template_tag for defining variables
SchrodingersGat Oct 25, 2020
1a4eb3f
Display which parts are "trackable" in a BOM table
SchrodingersGat Oct 26, 2020
24ab48e
Filter BOM table by "trackable" status
SchrodingersGat Oct 26, 2020
8f108d4
Add ability to filter BOM status by "validated" field
SchrodingersGat Oct 26, 2020
664dd00
Add database table for storing file attachments against a BuildOrder
SchrodingersGat Oct 26, 2020
7525bc2
Attachment functionality for BuildOrder
SchrodingersGat Oct 26, 2020
5e0d1fe
Allocate "non tracked" parts separately from tracked ones
SchrodingersGat Oct 26, 2020
b38fde8
Added some more buttons, etc
SchrodingersGat Oct 26, 2020
a4f6efc
Merge remote-tracking branch 'inventree/master' into build-fixes
SchrodingersGat Oct 26, 2020
9203f54
Bug fix - re-introduce settings_value custom tag
SchrodingersGat Oct 26, 2020
d8a0ab8
Fix for build table
SchrodingersGat Oct 26, 2020
4167e1f
Update translation files
SchrodingersGat Oct 26, 2020
b5e1d3f
Sorter fixes
SchrodingersGat Oct 26, 2020
06a3899
Disable "unallocate" button if there are not any allocations
SchrodingersGat Oct 26, 2020
54d5d28
Update javascript callbacks
SchrodingersGat Oct 27, 2020
646fe40
Require either serial or batch number to be set for trackable part
SchrodingersGat Oct 27, 2020
4055a36
Updated modal forms
SchrodingersGat Oct 27, 2020
170d55d
Add custom form validation step
SchrodingersGat Oct 27, 2020
22a5f92
Auto-generate build outputs when a build is created
SchrodingersGat Oct 27, 2020
3ec2396
Updated allocation card view
SchrodingersGat Oct 27, 2020
d06b4d7
Merge remote-tracking branch 'inventree/master' into build-fixes
SchrodingersGat Oct 28, 2020
091a9d9
Refactor how form errors are handled
SchrodingersGat Oct 28, 2020
ed8be52
Simplify display of possible conflicting parts
SchrodingersGat Oct 28, 2020
4a7e9a2
Update translations and PEP fixes
SchrodingersGat Oct 28, 2020
544b63c
Merge remote-tracking branch 'inventree/master' into build-fixes
SchrodingersGat Oct 28, 2020
551064b
Bugfix: BOM API now works slightly differently
SchrodingersGat Oct 28, 2020
a263d2f
Fixes for "auto allocate" concept
SchrodingersGat Oct 28, 2020
05ce17f
Tweaks
SchrodingersGat Oct 28, 2020
90cfb34
Merge remote-tracking branch 'inventree/master' into build-fixes
SchrodingersGat Oct 29, 2020
3a70226
Merge remote-tracking branch 'inventree/master' into build-fixes
SchrodingersGat Oct 30, 2020
95fadf1
Update unit testing
SchrodingersGat Oct 30, 2020
f1b83f1
Update fixtues for unit testing
SchrodingersGat Nov 1, 2020
b02c87e
Lots of work towards multiple build output
SchrodingersGat Nov 1, 2020
500da80
Add forms / views for creating a new build output, and completing the…
SchrodingersGat Nov 2, 2020
f5d0d54
Improve modal error message
SchrodingersGat Nov 2, 2020
05613b9
Further build tweaks / improvements
SchrodingersGat Nov 2, 2020
3f03adb
Bug fix for stock table
SchrodingersGat Nov 3, 2020
152801f
Dramatic speed improvements for build completion
SchrodingersGat Nov 3, 2020
b936f67
Various form fixes
SchrodingersGat Nov 3, 2020
2b91f69
Fix unit tests
SchrodingersGat Nov 3, 2020
ac03dab
Tweaks
SchrodingersGat Nov 3, 2020
8d0845d
Mark a build as "production" whenever a build output is created
SchrodingersGat Nov 3, 2020
5988e84
Add serial number suggestions
SchrodingersGat Nov 3, 2020
897d9b4
Update translation files
SchrodingersGat Nov 3, 2020
083dac1
Merge remote-tracking branch 'inventree/master' into build-fixes
SchrodingersGat Nov 3, 2020
3ea6719
Merge conflicting migration files
SchrodingersGat Nov 3, 2020
2e1a5a8
Bug fix for unit testing
SchrodingersGat Nov 3, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion InvenTree/InvenTree/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -337,7 +337,7 @@ def DownloadFile(data, filename, content_type='application/text'):
return response


def ExtractSerialNumbers(serials, expected_quantity):
def extract_serial_numbers(serials, expected_quantity):
""" Attempt to extract serial numbers from an input string.
- Serial numbers must be integer values
- Serial numbers must be positive
Expand Down
31 changes: 23 additions & 8 deletions InvenTree/InvenTree/static/script/inventree/inventree.js
Original file line number Diff line number Diff line change
Expand Up @@ -134,20 +134,35 @@ function makeProgressBar(value, maximum, opts={}) {

var extraclass = '';

if (maximum) {
// TODO - Special color?
}
else if (value > maximum) {
if (value > maximum) {
extraclass='progress-bar-over';
} else if (value < maximum) {
extraclass = 'progress-bar-under';
}

var text = value;
var style = options.style || '';

var text = '';

if (style == 'percent') {
// Display e.g. "50%"

text = `${percent}%`;
} else if (style == 'max') {
// Display just the maximum value
text = `${maximum}`;
} else if (style == 'value') {
// Display just the current value
text = `${value}`;
} else if (style == 'blank') {
// No display!
text = '';
} else {
/* Default style
* Display e.g. "5 / 10"
*/

if (maximum) {
text += ' / ';
text += maximum;
text = `${value} / ${maximum}`;
}

var id = options.id || 'progress-bar';
Expand Down
40 changes: 38 additions & 2 deletions InvenTree/InvenTree/static/script/inventree/modals.js
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,32 @@ function reloadFieldOptions(fieldName, options) {
}


function enableField(fieldName, enabled, options={}) {
/* Enable (or disable) a particular field in a modal.
*
* Args:
* - fieldName: The name of the field
* - enabled: boolean enabled / disabled status
* - options:
*/

var modal = options.modal || '#modal-form';

var field = getFieldByName(modal, fieldName);

field.prop("disabled", !enabled);
}

function clearField(fieldName, options={}) {

var modal = options.modal || '#modal-form';

var field = getFieldByName(modal, fieldName);

field.val("");
}


function partialMatcher(params, data) {
/* Replacement function for the 'matcher' parameter for a select2 dropdown.

Expand Down Expand Up @@ -696,6 +722,11 @@ function handleModalForm(url, options) {
}
// Form was returned, invalid!
else {

var warningDiv = $(modal).find('#form-validation-warning');

warningDiv.css('display', 'block');

if (response.html_form) {
injectModalForm(modal, response.html_form);

Expand Down Expand Up @@ -813,8 +844,13 @@ function launchModalForm(url, options = {}) {

$(modal).modal('hide');

// Permission denied!
if (xhr.status == 400) {
if (xhr.status == 0) {
// No response from the server
showAlertDialog(
"No Response",
"No response from the InvenTree server",
);
} else if (xhr.status == 400) {
showAlertDialog(
"Error 400: Bad Request",
"Server returned error code 400"
Expand Down
8 changes: 4 additions & 4 deletions InvenTree/InvenTree/status_codes.py
Original file line number Diff line number Diff line change
Expand Up @@ -214,25 +214,25 @@ class BuildStatus(StatusCode):

# Build status codes
PENDING = 10 # Build is pending / active
ALLOCATED = 20 # Parts have been removed from stock
PRODUCTION = 20 # BuildOrder is in production
CANCELLED = 30 # Build was cancelled
COMPLETE = 40 # Build is complete

options = {
PENDING: _("Pending"),
ALLOCATED: _("Allocated"),
PRODUCTION: _("Production"),
CANCELLED: _("Cancelled"),
COMPLETE: _("Complete"),
}

colors = {
PENDING: 'blue',
ALLOCATED: 'blue',
PRODUCTION: 'blue',
COMPLETE: 'green',
CANCELLED: 'red',
}

ACTIVE_CODES = [
PENDING,
ALLOCATED
PRODUCTION,
]
4 changes: 2 additions & 2 deletions InvenTree/InvenTree/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ class TestSerialNumberExtraction(TestCase):

def test_simple(self):

e = helpers.ExtractSerialNumbers
e = helpers.extract_serial_numbers

sn = e("1-5", 5)
self.assertEqual(len(sn), 5)
Expand All @@ -226,7 +226,7 @@ def test_simple(self):

def test_failures(self):

e = helpers.ExtractSerialNumbers
e = helpers.extract_serial_numbers

# Test duplicates
with self.assertRaises(ValidationError):
Expand Down
61 changes: 18 additions & 43 deletions InvenTree/InvenTree/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -213,26 +213,6 @@ def get_data(self):
"""
return {}

def pre_save(self, obj, form, **kwargs):
"""
Hook for doing something *before* an object is saved.

obj: The object to be saved
form: The cleaned form
"""

# Do nothing by default
pass

def post_save(self, obj, form, **kwargs):
"""
Hook for doing something *after* an object is saved.

"""

# Do nothing by default
pass

def validate(self, obj, form, **kwargs):
"""
Hook for performing custom form validation steps.
Expand Down Expand Up @@ -362,7 +342,7 @@ def get(self, request, *args, **kwargs):
form = self.get_form()
return self.renderJsonResponse(request, form)

def do_save(self, form):
def save(self, form):
"""
Method for actually saving the form to the database.
Default implementation is very simple,
Expand Down Expand Up @@ -393,7 +373,9 @@ def post(self, request, *args, **kwargs):

# Extra JSON data sent alongside form
data = {
'form_valid': valid
'form_valid': valid,
'form_errors': self.form.errors.as_json(),
'non_field_errors': self.form.non_field_errors().as_json(),
}

# Add in any extra class data
Expand All @@ -402,14 +384,8 @@ def post(self, request, *args, **kwargs):

if valid:

# Perform (optional) pre-save step
self.pre_save(None, self.form)

# Save the object to the database
self.do_save(self.form)

# Perform (optional) post-save step
self.post_save(self.object, self.form)
self.object = self.save(self.form)

# Return the PK of the newly-created object
data['pk'] = self.object.pk
Expand Down Expand Up @@ -440,11 +416,14 @@ def get(self, request, *args, **kwargs):

return self.renderJsonResponse(request, self.get_form(), context=self.get_context_data())

def do_save(self, form):
def save(self, object, form, **kwargs):
"""
Method for updating the object in the database.
Default implementation is very simple,
but can be overridden if required.
Default implementation is very simple, but can be overridden if required.

Args:
object - The current object, to be updated
form - The validated form
"""

self.object = form.save()
Expand Down Expand Up @@ -476,7 +455,9 @@ def post(self, request, *args, **kwargs):
valid = form.is_valid()

data = {
'form_valid': valid
'form_valid': valid,
'form_errors': form.errors.as_json(),
'non_field_errors': form.non_field_errors().as_json(),
}

# Add in any extra class data
Expand All @@ -485,22 +466,16 @@ def post(self, request, *args, **kwargs):

if valid:

# Perform (optional) pre-save step
self.pre_save(self.object, form)

# Save the updated objec to the database
obj = self.do_save(form)
self.save(self.object, form)

# Perform (optional) post-save step
self.post_save(obj, form)
self.object = self.get_object()

# Include context data about the updated object
data['pk'] = obj.pk

self.post_save(obj, form)
data['pk'] = self.object.pk

try:
data['url'] = obj.get_absolute_url()
data['url'] = self.object.get_absolute_url()
except AttributeError:
pass

Expand Down
24 changes: 18 additions & 6 deletions InvenTree/build/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,16 @@ def filter_queryset(self, queryset):

queryset = super().filter_queryset(queryset)

params = self.request.query_params

# Filter by build status?
status = self.request.query_params.get('status', None)
status = params.get('status', None)

if status is not None:
queryset = queryset.filter(status=status)

# Filter by "active" status
active = self.request.query_params.get('active', None)
# Filter by "pending" status
active = params.get('active', None)

if active is not None:
active = str2bool(active)
Expand All @@ -70,7 +72,7 @@ def filter_queryset(self, queryset):
queryset = queryset.exclude(status__in=BuildStatus.ACTIVE_CODES)

# Filter by associated part?
part = self.request.query_params.get('part', None)
part = params.get('part', None)

if part is not None:
queryset = queryset.filter(part=part)
Expand Down Expand Up @@ -119,14 +121,23 @@ def get_queryset(self):
return query

def filter_queryset(self, queryset):

queryset = super().filter_queryset(queryset)

params = self.request.query_params

# Does the user wish to filter by part?
part_pk = self.request.query_params.get('part', None)
part_pk = params.get('part', None)

if part_pk:
queryset = queryset.filter(stock_item__part=part_pk)

# Filter by output target
output = params.get('output', None)

if output:
queryset = queryset.filter(install_into=output)

return queryset

filter_backends = [
Expand All @@ -135,7 +146,8 @@ def filter_queryset(self, queryset):

filter_fields = [
'build',
'stock_item'
'stock_item',
'install_into',
]


Expand Down
50 changes: 49 additions & 1 deletion InvenTree/build/fixtures/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,52 @@
level: 0
lft: 0
rght: 0
tree_id: 1
tree_id: 1

- model: build.build
pk: 3
fields:
part: 50
reference: "0003"
title: 'Making things'
batch: 'B2'
status: 40 # COMPLETE
quantity: 21
notes: 'Some even more simple notes'
creation_date: '2019-03-16'
level: 0
lft: 0
rght: 0
tree_id: 1

- model: build.build
pk: 4
fields:
part: 50
reference: "0004"
title: 'Making things'
batch: 'B4'
status: 40 # COMPLETE
quantity: 21
notes: 'Some even even more simple notes'
creation_date: '2019-03-16'
level: 0
lft: 0
rght: 0
tree_id: 1

- model: build.build
pk: 5
fields:
part: 25
reference: "0005"
title: "Building some Widgets"
batch: "B10"
status: 40 # Complete
quantity: 10
creation_date: '2019-03-16'
notes: "A thing"
level: 0
lft: 0
rght: 0
tree_id: 1
Loading