mirror of
https://github.com/inventree/InvenTree.git
synced 2025-06-18 13:05:42 +00:00
Project code support (#4636)
* Support image uploads in the "notes" markdown fields - Implemented using the existing EasyMDE library - Copy / paste support - Drag / drop support * Remove debug message * Updated API version * Better UX when saving notes * Pin PIP version (for testing) * Bug fixes - Fix typo - Use correct serializer type * Add unit testing * Update role permissions * Typo fix * Update migration file * Adds a notes mixin class to be used for refactoring * Refactor existing models with notes to use the new mixin * Add helper function for finding all model types with a certain mixin * Refactor barcode plugin to use new method * Typo fix * Add daily task to delete old / unused notes * Add ProjectCode model (cherry picked from commit 382a0a2fc32c930d46ed3fe0c6d2cae654c2209d) * Adds IsStaffOrReadyOnly permissions - Authenticated users get read-only access - Staff users get read/write access (cherry picked from commit 53d04da86c4c866fd9c909d147d93844186470b4) * Adds API endpoints for project codes (cherry picked from commit 5ae1da23b2eae4e1168bc6fe28a3544dedc4a1b4) * Add migration file for projectcode model (cherry picked from commit 5f8717712c65df853ea69907d33e185fd91df7ee) * Add project code configuration page to the global settings view * Add 'project code' field to orders * Add ability to set / edit the project code for various order models * Add project code info to order list tables * Add configuration options for project code integration * Allow orders to be filtered by project code * Refactor table_filters.js - Allow orders to be filtered dynamically by project code * Bump API version * Fixes * Add resource mixin for exporting project code in order list * Add "has_project_code" filter * javascript fix * Edit / delete project codes via API - Also refactor some existing JS * Move MetadataMixin to InvenTree.models To prevent circular imports (cherry picked from commit d23b013881eaffe612dfbfcdfc5dff6d729068c6) * Fixes for circular imports * Add metadata for ProjectCode model * Add Metadata API endpoint for ProjectCode * Add unit testing for ProjectCode API endpoints
This commit is contained in:
35
InvenTree/templates/InvenTree/settings/project_codes.html
Normal file
35
InvenTree/templates/InvenTree/settings/project_codes.html
Normal file
@ -0,0 +1,35 @@
|
||||
{% extends "panel.html" %}
|
||||
|
||||
{% load i18n %}
|
||||
{% load inventree_extras %}
|
||||
|
||||
{% block label %}project-codes{% endblock label %}
|
||||
|
||||
{% block heading %}{% trans "Project Code Settings" %}{% endblock heading %}
|
||||
|
||||
|
||||
|
||||
{% block content %}
|
||||
|
||||
<!-- Project code settings -->
|
||||
<table class='table table-striped table-condensed'>
|
||||
<tbody>
|
||||
{% include "InvenTree/settings/setting.html" with key="PROJECT_CODES_ENABLED" icon='fa-toggle-on' %}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div class='panel-heading'>
|
||||
<div class='d-flex flex-span'>
|
||||
<h4>{% trans "Project Codes" %}</h4>
|
||||
{% include "spacer.html" %}
|
||||
<div class='btn-group' role='group'>
|
||||
<button class='btn btn-success' id='new-project-code'>
|
||||
<span class='fas fa-plus-circle'></span> {% trans "New Project Code" %}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<table class='table table-striped table-condensed' id='project-code-table'>
|
||||
</table>
|
||||
{% endblock content %}
|
@ -31,6 +31,7 @@
|
||||
{% include "InvenTree/settings/global.html" %}
|
||||
{% include "InvenTree/settings/login.html" %}
|
||||
{% include "InvenTree/settings/barcode.html" %}
|
||||
{% include "InvenTree/settings/project_codes.html" %}
|
||||
{% include "InvenTree/settings/notifications.html" %}
|
||||
{% include "InvenTree/settings/label.html" %}
|
||||
{% include "InvenTree/settings/report.html" %}
|
||||
|
@ -52,6 +52,78 @@ onPanelLoad('pricing', function() {
|
||||
});
|
||||
});
|
||||
|
||||
// Javascript for project codes panel
|
||||
onPanelLoad('project-codes', function() {
|
||||
|
||||
// Construct the project code table
|
||||
$('#project-code-table').bootstrapTable({
|
||||
url: '{% url "api-project-code-list" %}',
|
||||
search: true,
|
||||
sortable: true,
|
||||
formatNoMatches: function() {
|
||||
return '{% trans "No project codes found" %}';
|
||||
},
|
||||
columns: [
|
||||
{
|
||||
field: 'code',
|
||||
sortable: true,
|
||||
title: '{% trans "Project Code" %}',
|
||||
},
|
||||
{
|
||||
field: 'description',
|
||||
sortable: false,
|
||||
title: '{% trans "Description" %}',
|
||||
formatter: function(value, row) {
|
||||
let html = value;
|
||||
let buttons = '';
|
||||
|
||||
buttons += makeEditButton('button-project-code-edit', row.pk, '{% trans "Edit Project Code" %}');
|
||||
buttons += makeDeleteButton('button-project-code-delete', row.pk, '{% trans "Delete Project Code" %}');
|
||||
|
||||
html += wrapButtons(buttons);
|
||||
return html;
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
$('#project-code-table').on('click', '.button-project-code-edit', function() {
|
||||
let pk = $(this).attr('pk');
|
||||
|
||||
constructForm(`{% url "api-project-code-list" %}${pk}/`, {
|
||||
title: '{% trans "Edit Project Code" %}',
|
||||
fields: {
|
||||
code: {},
|
||||
description: {},
|
||||
},
|
||||
refreshTable: '#project-code-table',
|
||||
});
|
||||
});
|
||||
|
||||
$('#project-code-table').on('click', '.button-project-code-delete', function() {
|
||||
let pk = $(this).attr('pk');
|
||||
|
||||
constructForm(`{% url "api-project-code-list" %}${pk}/`, {
|
||||
title: '{% trans "Delete Project Code" %}',
|
||||
method: 'DELETE',
|
||||
refreshTable: '#project-code-table',
|
||||
});
|
||||
});
|
||||
|
||||
$('#new-project-code').click(function() {
|
||||
// Construct a new project code
|
||||
constructForm('{% url "api-project-code-list" %}', {
|
||||
fields: {
|
||||
code: {},
|
||||
description: {},
|
||||
},
|
||||
title: '{% trans "New Project Code" %}',
|
||||
method: 'POST',
|
||||
refreshTable: '#project-code-table',
|
||||
});
|
||||
})
|
||||
});
|
||||
|
||||
// Javascript for Part Category panel
|
||||
onPanelLoad('category', function() {
|
||||
$('#category-select').select2({
|
||||
@ -136,11 +208,12 @@ onPanelLoad('category', function() {
|
||||
title: '{% trans "Default Value" %}',
|
||||
sortable: 'true',
|
||||
formatter: function(value, row, index, field) {
|
||||
var bEdit = "<button title='{% trans "Edit Template" %}' class='template-edit btn btn-outline-secondary' type='button' pk='" + row.pk + "'><span class='fas fa-edit'></span></button>";
|
||||
var bDel = "<button title='{% trans "Delete Template" %}' class='template-delete btn btn-outline-secondary' type='button' pk='" + row.pk + "'><span class='fas fa-trash-alt icon-red'></span></button>";
|
||||
let buttons = '';
|
||||
buttons += makeEditButton('template-edit', row.pk, '{% trans "Edit Template" %}');
|
||||
buttons += makeDeleteButton('template-delete', row.pk, '{% trans "Delete Template" %}');
|
||||
|
||||
var html = value
|
||||
html += "<div class='btn-group float-right' role='group'>" + bEdit + bDel + "</div>";
|
||||
let html = value
|
||||
html += wrapButtons(buttons);
|
||||
|
||||
return html;
|
||||
}
|
||||
@ -154,6 +227,7 @@ onPanelLoad('category', function() {
|
||||
var pk = $(this).attr('pk');
|
||||
|
||||
constructForm(`/api/part/category/parameters/${pk}/`, {
|
||||
title: '{% trans "Edit Category Parameter Template" %}',
|
||||
fields: {
|
||||
parameter_template: {},
|
||||
category: {
|
||||
|
@ -30,6 +30,8 @@
|
||||
{% include "sidebar_item.html" with label='login' text=text icon="fa-fingerprint" %}
|
||||
{% trans "Barcode Support" as text %}
|
||||
{% include "sidebar_item.html" with label='barcodes' text=text icon="fa-qrcode" %}
|
||||
{% trans "Project Codes" as text %}
|
||||
{% include "sidebar_item.html" with label='project-codes' text=text icon="fa-list" %}
|
||||
{% trans "Notifications" as text %}
|
||||
{% include "sidebar_item.html" with label='global-notifications' text=text icon="fa-bell" %}
|
||||
{% trans "Pricing" as text %}
|
||||
|
@ -1123,9 +1123,9 @@ function loadSupplierPartTable(table, url, options) {
|
||||
var params = options.params || {};
|
||||
|
||||
// Load filters
|
||||
var filters = loadTableFilters('supplier-part', params);
|
||||
var filters = loadTableFilters('supplierpart', params);
|
||||
|
||||
setupFilterList('supplier-part', $(table));
|
||||
setupFilterList('supplierpart', $(table));
|
||||
|
||||
$(table).inventreeTable({
|
||||
url: url,
|
||||
|
@ -16,6 +16,7 @@
|
||||
renderOwner,
|
||||
renderPart,
|
||||
renderPartCategory,
|
||||
renderProjectCode,
|
||||
renderReturnOrder,
|
||||
renderStockItem,
|
||||
renderStockLocation,
|
||||
@ -78,6 +79,8 @@ function getModelRenderer(model) {
|
||||
return renderUser;
|
||||
case 'group':
|
||||
return renderGroup;
|
||||
case 'projectcode':
|
||||
return renderProjectCode;
|
||||
default:
|
||||
// Un-handled model type
|
||||
console.error(`Rendering not implemented for model '${model}'`);
|
||||
@ -476,3 +479,16 @@ function renderSupplierPart(data, parameters={}) {
|
||||
parameters
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
// Renderer for "ProjectCode" model
|
||||
function renderProjectCode(data, parameters={}) {
|
||||
|
||||
return renderModel(
|
||||
{
|
||||
text: data.code,
|
||||
textSecondary: data.description,
|
||||
},
|
||||
parameters
|
||||
);
|
||||
}
|
||||
|
@ -62,6 +62,9 @@ function purchaseOrderFields(options={}) {
|
||||
}
|
||||
},
|
||||
supplier_reference: {},
|
||||
project_code: {
|
||||
icon: 'fa-list',
|
||||
},
|
||||
target_date: {
|
||||
icon: 'fa-calendar-alt',
|
||||
},
|
||||
@ -126,6 +129,10 @@ function purchaseOrderFields(options={}) {
|
||||
};
|
||||
}
|
||||
|
||||
if (!global_settings.PROJECT_CODES_ENABLED) {
|
||||
delete fields.project_code;
|
||||
}
|
||||
|
||||
return fields;
|
||||
}
|
||||
|
||||
@ -1614,6 +1621,18 @@ function loadPurchaseOrderTable(table, options) {
|
||||
field: 'description',
|
||||
title: '{% trans "Description" %}',
|
||||
},
|
||||
{
|
||||
field: 'project_code',
|
||||
title: '{% trans "Project Code" %}',
|
||||
switchable: global_settings.PROJECT_CODES_ENABLED,
|
||||
visible: global_settings.PROJECT_CODES_ENABLED,
|
||||
sortable: true,
|
||||
formatter: function(value, row) {
|
||||
if (row.project_code_detail) {
|
||||
return `<span title='${row.project_code_detail.description}'>${row.project_code_detail.code}</span>`;
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
field: 'status',
|
||||
title: '{% trans "Status" %}',
|
||||
|
@ -46,6 +46,9 @@ function returnOrderFields(options={}) {
|
||||
}
|
||||
},
|
||||
customer_reference: {},
|
||||
project_code: {
|
||||
icon: 'fa-list',
|
||||
},
|
||||
target_date: {
|
||||
icon: 'fa-calendar-alt',
|
||||
},
|
||||
@ -69,6 +72,10 @@ function returnOrderFields(options={}) {
|
||||
}
|
||||
};
|
||||
|
||||
if (!global_settings.PROJECT_CODES_ENABLED) {
|
||||
delete fields.project_code;
|
||||
}
|
||||
|
||||
return fields;
|
||||
}
|
||||
|
||||
@ -271,6 +278,18 @@ function loadReturnOrderTable(table, options={}) {
|
||||
field: 'description',
|
||||
title: '{% trans "Description" %}',
|
||||
},
|
||||
{
|
||||
field: 'project_code',
|
||||
title: '{% trans "Project Code" %}',
|
||||
switchable: global_settings.PROJECT_CODES_ENABLED,
|
||||
visible: global_settings.PROJECT_CODES_ENABLED,
|
||||
sortable: true,
|
||||
formatter: function(value, row) {
|
||||
if (row.project_code_detail) {
|
||||
return `<span title='${row.project_code_detail.description}'>${row.project_code_detail.code}</span>`;
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
sortable: true,
|
||||
field: 'status',
|
||||
|
@ -59,6 +59,9 @@ function salesOrderFields(options={}) {
|
||||
}
|
||||
},
|
||||
customer_reference: {},
|
||||
project_code: {
|
||||
icon: 'fa-list',
|
||||
},
|
||||
target_date: {
|
||||
icon: 'fa-calendar-alt',
|
||||
},
|
||||
@ -82,6 +85,10 @@ function salesOrderFields(options={}) {
|
||||
}
|
||||
};
|
||||
|
||||
if (!global_settings.PROJECT_CODES_ENABLED) {
|
||||
delete fields.project_code;
|
||||
}
|
||||
|
||||
return fields;
|
||||
}
|
||||
|
||||
@ -739,6 +746,18 @@ function loadSalesOrderTable(table, options) {
|
||||
field: 'description',
|
||||
title: '{% trans "Description" %}',
|
||||
},
|
||||
{
|
||||
field: 'project_code',
|
||||
title: '{% trans "Project Code" %}',
|
||||
switchable: global_settings.PROJECT_CODES_ENABLED,
|
||||
visible: global_settings.PROJECT_CODES_ENABLED,
|
||||
sortable: true,
|
||||
formatter: function(value, row) {
|
||||
if (row.project_code_detail) {
|
||||
return `<span title='${row.project_code_detail.description}'>${row.project_code_detail.code}</span>`;
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
sortable: true,
|
||||
field: 'status',
|
||||
|
File diff suppressed because it is too large
Load Diff
11
InvenTree/templates/project_code_data.html
Normal file
11
InvenTree/templates/project_code_data.html
Normal file
@ -0,0 +1,11 @@
|
||||
{% load i18n %}
|
||||
|
||||
{% if instance and instance.project_code %}
|
||||
<tr>
|
||||
<td><span class='fas fa-list'></span></td>
|
||||
<td>{% trans "Project Code" %}</td>
|
||||
<td>
|
||||
{{ instance.project_code.code }} - <em><small>{{ instance.project_code.description }}</small></em>
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
Reference in New Issue
Block a user