mirror of
https://github.com/inventree/InvenTree.git
synced 2025-06-18 13:05:42 +00:00
Merge branch 'inventree:master' into matmair/issue2279
This commit is contained in:
@ -77,7 +77,7 @@
|
||||
{% endif %}
|
||||
|
||||
{% if plugin.website %}
|
||||
<a href="{{ plugin.website }}"><i class="fas fa-globe"></i></a>
|
||||
<a href="{{ plugin.website }}"><span class="fas fa-globe"></span></a>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>{{ plugin.author }}</td>
|
||||
|
@ -65,7 +65,7 @@
|
||||
<input id="email_radio_{{forloop.counter}}" type="radio" name="email" {% if emailaddress.primary or user.emailaddress_set.count == 1 %}checked="checked" {%endif %} value="{{emailaddress.email}}" />
|
||||
|
||||
{% if emailaddress.primary %}
|
||||
<b>{{ emailaddress.email }}</b>
|
||||
<strong>{{ emailaddress.email }}</strong>
|
||||
{% else %}
|
||||
{{ emailaddress.email }}
|
||||
{% endif %}
|
||||
|
@ -94,7 +94,7 @@
|
||||
{% if server_restart_required and not demo_mode %}
|
||||
<div id='alert-restart-server' class='alert alert-danger' role='alert'>
|
||||
<span class='fas fa-server'></span>
|
||||
<b>{% trans "Server Restart Required" %}</b>
|
||||
<strong>{% trans "Server Restart Required" %}</strong>
|
||||
<small>
|
||||
<br>
|
||||
{% trans "A configuration option has been changed which requires a server restart" %}. {% trans "Contact your system administrator for further information" %}
|
||||
|
@ -21,6 +21,7 @@
|
||||
/* exported
|
||||
allocateStockToBuild,
|
||||
completeBuildOrder,
|
||||
createBuildOutput,
|
||||
editBuildOrder,
|
||||
loadAllocationTable,
|
||||
loadBuildOrderAllocationTable,
|
||||
@ -175,6 +176,85 @@ function completeBuildOrder(build_id, options={}) {
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Construct a new build output against the provided build
|
||||
*/
|
||||
function createBuildOutput(build_id, options) {
|
||||
|
||||
// Request build order information from the server
|
||||
inventreeGet(
|
||||
`/api/build/${build_id}/`,
|
||||
{},
|
||||
{
|
||||
success: function(build) {
|
||||
|
||||
var html = '';
|
||||
|
||||
var trackable = build.part_detail.trackable;
|
||||
var remaining = Math.max(0, build.quantity - build.completed);
|
||||
|
||||
var fields = {
|
||||
quantity: {
|
||||
value: remaining,
|
||||
},
|
||||
serial_numbers: {
|
||||
hidden: !trackable,
|
||||
required: options.trackable_parts || trackable,
|
||||
},
|
||||
batch_code: {},
|
||||
auto_allocate: {
|
||||
hidden: !trackable,
|
||||
},
|
||||
};
|
||||
|
||||
// Work out the next available serial numbers
|
||||
inventreeGet(`/api/part/${build.part}/serial-numbers/`, {}, {
|
||||
success: function(data) {
|
||||
if (data.next) {
|
||||
fields.serial_numbers.placeholder = `{% trans "Next available serial number" %}: ${data.next}`;
|
||||
} else {
|
||||
fields.serial_numbers.placeholder = `{% trans "Latest serial number" %}: ${data.latest}`;
|
||||
}
|
||||
},
|
||||
async: false,
|
||||
});
|
||||
|
||||
if (options.trackable_parts) {
|
||||
html += `
|
||||
<div class='alert alert-block alert-info'>
|
||||
{% trans "The Bill of Materials contains trackable parts" %}.<br>
|
||||
{% trans "Build outputs must be generated individually" %}.
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
if (trackable) {
|
||||
html += `
|
||||
<div class='alert alert-block alert-info'>
|
||||
{% trans "Trackable parts can have serial numbers specified" %}<br>
|
||||
{% trans "Enter serial numbers to generate multiple single build outputs" %}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
constructForm(`/api/build/${build_id}/create-output/`, {
|
||||
method: 'POST',
|
||||
title: '{% trans "Create Build Output" %}',
|
||||
confirm: true,
|
||||
fields: fields,
|
||||
preFormContent: html,
|
||||
onSuccess: function(response) {
|
||||
location.reload();
|
||||
},
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Construct a set of output buttons for a particular build output
|
||||
*/
|
||||
@ -1435,8 +1515,22 @@ function allocateStockToBuild(build_id, part_id, bom_items, options={}) {
|
||||
// ID of the associated "build output" (or null)
|
||||
var output_id = options.output || null;
|
||||
|
||||
var auto_fill_filters = {};
|
||||
|
||||
var source_location = options.source_location;
|
||||
|
||||
if (output_id) {
|
||||
// Request information on the particular build output (stock item)
|
||||
inventreeGet(`/api/stock/${output_id}/`, {}, {
|
||||
success: function(output) {
|
||||
if (output.quantity == 1 && output.serial != null) {
|
||||
auto_fill_filters.serial = output.serial;
|
||||
}
|
||||
},
|
||||
async: false,
|
||||
});
|
||||
}
|
||||
|
||||
function renderBomItemRow(bom_item, quantity) {
|
||||
|
||||
var pk = bom_item.pk;
|
||||
@ -1623,7 +1717,9 @@ function allocateStockToBuild(build_id, part_id, bom_items, options={}) {
|
||||
required: true,
|
||||
render_part_detail: true,
|
||||
render_location_detail: true,
|
||||
render_stock_id: false,
|
||||
auto_fill: true,
|
||||
auto_fill_filters: auto_fill_filters,
|
||||
onSelect: function(data, field, opts) {
|
||||
// Adjust the 'quantity' field based on availability
|
||||
|
||||
|
@ -1696,13 +1696,19 @@ function initializeRelatedField(field, fields, options={}) {
|
||||
} else if (field.auto_fill) {
|
||||
// Attempt to auto-fill the field
|
||||
|
||||
var filters = field.filters || {};
|
||||
var filters = {};
|
||||
|
||||
// Update with nominal field fields
|
||||
Object.assign(filters, field.filters || {});
|
||||
|
||||
// Update with filters only used for initial filtering
|
||||
Object.assign(filters, field.auto_fill_filters || {});
|
||||
|
||||
// Enforce pagination, limit to a single return (for fast query)
|
||||
filters.limit = 1;
|
||||
filters.offset = 0;
|
||||
|
||||
inventreeGet(field.api_url, field.filters || {}, {
|
||||
inventreeGet(field.api_url, filters || {}, {
|
||||
success: function(data) {
|
||||
|
||||
// Only a single result is available, given the provided filters
|
||||
@ -2014,7 +2020,7 @@ function constructField(name, parameters, options) {
|
||||
if (parameters.help_text && !options.hideLabels) {
|
||||
|
||||
// Boolean values are handled differently!
|
||||
if (parameters.type != 'boolean') {
|
||||
if (parameters.type != 'boolean' && !parameters.hidden) {
|
||||
html += constructHelpText(name, parameters, options);
|
||||
}
|
||||
}
|
||||
@ -2022,7 +2028,6 @@ function constructField(name, parameters, options) {
|
||||
// Div for error messages
|
||||
html += `<div id='errors-${field_name}'></div>`;
|
||||
|
||||
|
||||
html += `</div>`; // controls
|
||||
html += `</div>`; // form-group
|
||||
|
||||
@ -2212,6 +2217,10 @@ function constructInputOptions(name, classes, type, parameters, options={}) {
|
||||
return `<textarea ${opts.join(' ')}></textarea>`;
|
||||
} else if (parameters.type == 'boolean') {
|
||||
|
||||
if (parameters.hidden) {
|
||||
return '';
|
||||
}
|
||||
|
||||
var help_text = '';
|
||||
|
||||
if (!options.hideLabels && parameters.help_text) {
|
||||
|
98
InvenTree/templates/patterns/wizard/match_fields.html
Normal file
98
InvenTree/templates/patterns/wizard/match_fields.html
Normal file
@ -0,0 +1,98 @@
|
||||
{% load inventree_extras %}
|
||||
{% load i18n %}
|
||||
{% load static %}
|
||||
|
||||
{% block form_alert %}
|
||||
{% if missing_columns and missing_columns|length > 0 %}
|
||||
<div class='alert alert-danger alert-block' style='margin-top:12px;' role='alert'>
|
||||
{% trans "Missing selections for the following required columns" %}:
|
||||
<br>
|
||||
<ul>
|
||||
{% for col in missing_columns %}
|
||||
<li>{{ col }}</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if duplicates and duplicates|length > 0 %}
|
||||
<div class='alert alert-danger alert-block' role='alert'>
|
||||
{% trans "Duplicate selections found, see below. Fix them then retry submitting." %}
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock form_alert %}
|
||||
|
||||
{% block form_buttons_top %}
|
||||
{% if wizard.steps.prev %}
|
||||
<button name='wizard_goto_step' type='submit' value='{{ wizard.steps.prev }}' class='save btn btn-outline-secondary'>{% trans "Previous Step" %}</button>
|
||||
{% endif %}
|
||||
<button type='submit' class='save btn btn-outline-secondary'>{% trans "Submit Selections" %}</button>
|
||||
{% endblock form_buttons_top %}
|
||||
|
||||
{% block form_content %}
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{% trans "File Fields" %}</th>
|
||||
<th></th>
|
||||
{% for col in form %}
|
||||
<th>
|
||||
<div>
|
||||
<input type='hidden' name='col_name_{{ forloop.counter0 }}' value='{{ col.name }}'/>
|
||||
{{ col.name }}
|
||||
<button class='btn btn-outline-secondary btn-remove' onClick='removeColFromBomWizard()' id='del_col_{{ forloop.counter0 }}' style='display: inline; float: right;' title='{% trans "Remove column" %}'>
|
||||
<span col_id='{{ forloop.counter0 }}' class='fas fa-trash-alt icon-red'></span>
|
||||
</button>
|
||||
</div>
|
||||
</th>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>{% trans "Match Fields" %}</td>
|
||||
<td></td>
|
||||
{% for col in form %}
|
||||
<td>
|
||||
{{ col }}
|
||||
{% for duplicate in duplicates %}
|
||||
{% if duplicate == col.value %}
|
||||
<div class='alert alert-danger alert-block text-center' role='alert' style='padding:2px; margin-top:6px; margin-bottom:2px'>
|
||||
<strong>{% trans "Duplicate selection" %}</strong>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</td>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
{% for row in rows %}
|
||||
{% with forloop.counter as row_index %}
|
||||
<tr>
|
||||
<td style='width: 32px;'>
|
||||
<button class='btn btn-outline-secondary btn-remove' onClick='removeRowFromBomWizard()' id='del_row_{{ row_index }}' style='display: inline; float: left;' title='{% trans "Remove row" %}'>
|
||||
<span row_id='{{ row_index }}' class='fas fa-trash-alt icon-red'></span>
|
||||
</button>
|
||||
</td>
|
||||
<td style='text-align: left;'>{{ row_index }}</td>
|
||||
{% for item in row.data %}
|
||||
<td>
|
||||
<input type='hidden' name='row_{{ row_index }}_col_{{ forloop.counter0 }}' value='{{ item }}'/>
|
||||
{{ item }}
|
||||
</td>
|
||||
{% endfor %}
|
||||
</tr>
|
||||
{% endwith %}
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
{% endblock form_content %}
|
||||
|
||||
{% block form_buttons_bottom %}
|
||||
{% endblock form_buttons_bottom %}
|
||||
|
||||
{% block js_ready %}
|
||||
{{ block.super }}
|
||||
|
||||
$('.fieldselect').select2({
|
||||
width: '100%',
|
||||
matcher: partialMatcher,
|
||||
});
|
||||
|
||||
{% endblock %}
|
45
InvenTree/templates/patterns/wizard/upload.html
Normal file
45
InvenTree/templates/patterns/wizard/upload.html
Normal file
@ -0,0 +1,45 @@
|
||||
<div class='panel' id='{{ panel_id }}'>
|
||||
<div class='panel-heading'>
|
||||
<h4>
|
||||
{{ header_text }}
|
||||
{{ wizard.form.media }}
|
||||
</h4>
|
||||
</div>
|
||||
<div class='panel-content'>
|
||||
{% if upload_go_ahead %}
|
||||
|
||||
<p>{% blocktrans with step=wizard.steps.step1 count=wizard.steps.count %}Step {{step}} of {{count}}{% endblocktrans %}
|
||||
{% if description %}- {{ description }}{% endif %}</p>
|
||||
|
||||
{% block form_alert %}
|
||||
{% endblock form_alert %}
|
||||
|
||||
<form action='' method='post' class='js-modal-form' enctype='multipart/form-data'>
|
||||
{% csrf_token %}
|
||||
{% load crispy_forms_tags %}
|
||||
|
||||
{% block form_buttons_top %}
|
||||
{% endblock form_buttons_top %}
|
||||
|
||||
<table class='table table-striped' style='margin-top: 12px; margin-bottom: 0px'>
|
||||
{{ wizard.management_form }}
|
||||
{% block form_content %}
|
||||
{% crispy wizard.form %}
|
||||
{% endblock form_content %}
|
||||
</table>
|
||||
|
||||
{% block form_buttons_bottom %}
|
||||
{% if wizard.steps.prev %}
|
||||
<button name='wizard_goto_step' type='submit' value='{{ wizard.steps.prev }}' class='save btn btn-outline-secondary'>{% trans "Previous Step" %}</button>
|
||||
{% endif %}
|
||||
<button type='submit' class='save btn btn-outline-secondary'>{% trans "Upload File" %}</button>
|
||||
</form>
|
||||
{% endblock form_buttons_bottom %}
|
||||
|
||||
{% else %}
|
||||
<div class='alert alert-danger alert-block' role='alert'>
|
||||
{{ error_text }}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
@ -1,7 +1,7 @@
|
||||
{% load i18n %}
|
||||
<span title='{{ text }}' class="list-group-item sidebar-list-group-item border-end d-inline-block text-truncate bg-light" data-bs-parent="#sidebar">
|
||||
<h6>
|
||||
<i class="bi bi-bootstrap"></i>
|
||||
<span class="bi bi-bootstrap"></span>
|
||||
{% if icon %}<span class='sidebar-item-icon fas {{ icon }}'></span>{% endif %}
|
||||
{% if text %}<span class='sidebar-item-text' style='display: none;'><strong>{{ text }}</strong></span>{% endif %}
|
||||
</h6>
|
||||
|
@ -1,6 +1,6 @@
|
||||
{% load i18n %}
|
||||
<a href="#" id='select-{{ label }}' title='{{ text }}' class="list-group-item sidebar-list-group-item border-end d-inline-block text-truncate sidebar-selector" data-bs-parent="#sidebar">
|
||||
<i class="bi bi-bootstrap"></i>
|
||||
<span class="bi bi-bootstrap"></span>
|
||||
<span class='sidebar-item-icon fas {{ icon|default:"fa-circle" }}'></span>
|
||||
<span class='sidebar-item-text' style='display: none;'>{{ text }}</span>
|
||||
{% if badge %}
|
||||
|
@ -1,4 +1,4 @@
|
||||
{% load i18n %}
|
||||
<a href="{{ url }}" class="list-group-item sidebar-list-group-item border-end d-inline-block text-truncate" data-bs-parent="#sidebar">
|
||||
<i class="bi bi-bootstrap"></i><span class='sidebar-item-icon fas {{ icon }}'></span><span class='sidebar-item-text' style='display: none;'>{{ text }}</span>
|
||||
<span class="bi bi-bootstrap"></span><span class='sidebar-item-icon fas {{ icon }}'></span><span class='sidebar-item-text' style='display: none;'>{{ text }}</span>
|
||||
</a>
|
||||
|
@ -1,4 +1,4 @@
|
||||
<a href="#" id='{{ target }}-toggle' class="list-group-item sidebar-list-group-item border-end d-inline-block text-truncate sidebar-toggle" data-bs-parent="#sidebar" style='display: none;'>
|
||||
<i class="bi bi-bootstrap"></i><span id='sidebar-toggle-icon' class='sidebar-item-icon fas fa-chevron-left'></span>
|
||||
<span class="bi bi-bootstrap"></span><span id='sidebar-toggle-icon' class='sidebar-item-icon fas fa-chevron-left'></span>
|
||||
{% if text %}<span class='sidebar-item-text' style='display: none;'>{{ text }}</span>{% endif %}
|
||||
</a>
|
||||
|
Reference in New Issue
Block a user