2
0
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:
Matthias Mair
2022-02-16 02:02:02 +01:00
committed by GitHub
91 changed files with 848 additions and 724 deletions

View File

@ -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>

View File

@ -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 %}

View File

@ -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" %}

View File

@ -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

View File

@ -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) {

View 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 %}

View 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>

View File

@ -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>

View File

@ -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 %}

View File

@ -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>

View File

@ -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>