mirror of
https://github.com/inventree/InvenTree.git
synced 2025-07-09 07:00:56 +00:00
[Feature] Add RMA support (#4488)
* Adds ReturnOrder and ReturnOrderAttachment models
* Adds new 'role' specific for return orders
* Refactor total_price into a mixin
- Required for PurchaseOrder and SalesOrder
- May not be required for ReturnOrder (remains to be seen)
* Adds API endpoints for ReturnOrder
- Add list endpoint
- Add detail endpoint
- Adds required serializer models
* Adds basic "index" page for Return Order model
* Update API version
* Update navbar text
* Add db migration for new "role"
* Add ContactList and ContactDetail API endpoints
* Adds template and JS code for manipulation of contacts
- Display a table
- Create / edit / delete
* Splits order.js into multiple files
- Javascript files was becoming extremely large
- Hard to debug and find code
- Split into purchase_order / return_order / sales_order
* Fix role name (change 'returns' to 'return_order')
- Similar to existing roles for purchase_order and sales_order
* Adds detail page for ReturnOrder
* URL cleanup
- Use <int:pk> instead of complex regex
* More URL cleanup
* Add "return orders" list to company detail page
* Break JS status codes into new javascript file
- Always difficult to track down where these are rendered
- Enough to warrant their own file now
* Add ability to edit return order from detail page
* Database migrations
- Add new ReturnOrder modeles
- Add new 'contact' field to external orders
* Adds "contact" to ReturnOrder
- Implement check to ensure that the selected "contact" matches the selected "company"
* Adjust filters to limit contact options
* Fix typo
* Expose 'contact' field for PurchaseOrder model
* Render contact information
* Add "contact" for SalesOrder
* Adds setting to enable / disable return order functionality
- Simply hides the navigation elements
- API is not disabled
* Support filtering ReturnOrder by 'status'
- Refactors existing filter into the OrderFilter class
* js linting
* More JS linting
* Adds ReturnOrderReport model
* Add serializer for the ReturnOrderReport model
- A little bit of refactoring along the way
* Admin integration for new report model
* Refactoring for report.api
- Adds generic mixins for filtering queryset (based on updates to label.api)
- Reduces repeated code a *lot*
* Exposes API endpoints for ReturnOrderReport
* Adds default example report file for ReturnOrder
- Requires some more work :)
* Refactor report printing javascript code
- Replace all existing functions with 'printReports'
* Improvements for default StockItem test report template
- Fix bug in template
- Handle potential errors in template tags
- Add more helpers to report tags
- Improve test result rendering
* Reduce logging verbosity from weasyprint
* Refactor javascript for label printing
- Consolidate into a single function
- Similar to refactor of report functions
* Add report print button to return order page
* Record user reference when creating via API
* Refactor order serializers
- Move common code into AbstractOrderSerializer class
* Adds extra line item model for the return order
- Adds serializer and API endpoints as appropriate
* Render extra line table for return order
- Refactor existing functions into a single generic function
- Reduces repeated JS code a lot
* Add ability to create a new extra line item
* Adds button for creating a new lien item
* JS linting
* Update test
* Typo fix
(cherry picked from commit 28ac2be35b
)
* Enable search for return order
* Don't do pricing (yet) for returnorder extra line table
- Fixes an uncaught error
* Error catching for api.js
* Updates for order models:
- Add 'target_date' field to abstract Order model
- Add IN_PROGRESS status code for return order
- Refactor 'overdue' and 'outstanding' API queries
- Refactor OVERDUE_FILTER on order models
- Refactor is_overdue on order models
- More table filters for return order model
* JS cleanup
* Create ReturnOrderLineItem model
- New type of status label
- Add TotalPriceMixin to ReturnOrder model
* Adds an API serializer for the ReturnOrderLineItem model
* Add API endpoints for ReturnOrderLineItem model
- Including some refactoring along the way
* javascript: refactor loadTableFilters function
- Pass enforced query through to the filters
- Call Object.assign() to construct a superset query
- Removes a lot of code duplication
* Refactor hard-coded URLS to use {% url %} lookup
- Forces error if the URL is wrong
- If we ever change the URL, will still work
* Implement creation of new return order line items
* Adds 'part_detail' annotation to ReturnOrderLineItem serializer
- Required for rendering part information
* javascript: refactor method for creating a group of buttons in a table
* javascript: refactor common buttons with helper functions
* Allow edit and delete of return order line items
* Add form option to automatically reload a table on success
- Pass table name to options.refreshTable
* JS linting
* Add common function for createExtraLineItem
* Refactor loading of attachment tables
- Setup drag-and-drop as part of core function
* CI fixes
* Refactoring out some more common API endpoint code
* Update migrations
* Fix permission typo
* Refactor for unit testing code
* Add unit tests for Contact model
* Tests for returnorder list API
* Annotate 'line_items' to ReturnOrder serializer
* Driving the refactor tractor
* More unit tests for the ReturnOrder API endpoints
* Refactor "print orders" button for various order tables
- Move into "setupFilterList" code (generic)
* add generic 'label printing' button to table actions buttons
* Refactor build output table
* Refactoring icon generation for js
* Refactoring for Part API
* Fix database model type for 'received_date'
* Add API endpoint to "issue" a ReturnOrder
* Improvements for stock tracking table
- Add new status codes
- Add rendering for SalesOrder
- Add rendering for ReturnOrder
- Fix status badges
* Adds functionality to receive line items against a return order
* Add endpoints for completing and cancelling orders
* Add option to allow / prevent editing of ReturnOrder after completed
* js linting
* Wrap "add extra line" button in setting check
* Updates to order/admin.py
* Remove inline admin for returnorderline model
* Updates to pass CI
* Serializer fix
* order template fixes
* Unit test fix
* Fixes for ReturnOrder.receive_line_item
* Unit testing for receiving line items against an RMA
* Improve example report for return order
* Extend unit tests for reporting
* Cleanup here and there
* Unit testing for order views
* Clear "sales_order" field when returning against ReturnOrder
* Add 'location' to deltas when returning from customer
* Bug fix for unit test
This commit is contained in:
@ -4,23 +4,26 @@
|
||||
constructForm,
|
||||
imageHoverIcon,
|
||||
loadTableFilters,
|
||||
makeIconButton,
|
||||
renderLink,
|
||||
setupFilterList,
|
||||
*/
|
||||
|
||||
/* exported
|
||||
createCompany,
|
||||
createContact,
|
||||
createManufacturerPart,
|
||||
createSupplierPart,
|
||||
createSupplierPartPriceBreak,
|
||||
deleteContacts,
|
||||
deleteManufacturerParts,
|
||||
deleteManufacturerPartParameters,
|
||||
deleteSupplierParts,
|
||||
duplicateSupplierPart,
|
||||
editCompany,
|
||||
editContact,
|
||||
editSupplierPartPriceBreak,
|
||||
loadCompanyTable,
|
||||
loadContactTable,
|
||||
loadManufacturerPartTable,
|
||||
loadManufacturerPartParameterTable,
|
||||
loadSupplierPartTable,
|
||||
@ -197,7 +200,7 @@ function createSupplierPart(options={}) {
|
||||
var header = '';
|
||||
if (options.part) {
|
||||
var part_model = {};
|
||||
inventreeGet(`/api/part/${options.part}/.*`, {}, {
|
||||
inventreeGet(`{% url "api-part-list" %}${options.part}/.*`, {}, {
|
||||
async: false,
|
||||
success: function(response) {
|
||||
part_model = response;
|
||||
@ -226,7 +229,7 @@ function duplicateSupplierPart(part, options={}) {
|
||||
var fields = options.fields || supplierPartFields();
|
||||
|
||||
// Retrieve information for the supplied part
|
||||
inventreeGet(`/api/company/part/${part}/`, {}, {
|
||||
inventreeGet(`{% url "api-supplier-part-list" %}${part}/`, {}, {
|
||||
success: function(data) {
|
||||
|
||||
// Remove fields which we do not want to duplicate
|
||||
@ -234,7 +237,7 @@ function duplicateSupplierPart(part, options={}) {
|
||||
delete data['available'];
|
||||
delete data['availability_updated'];
|
||||
|
||||
constructForm(`/api/company/part/`, {
|
||||
constructForm('{% url "api-supplier-part-list" %}', {
|
||||
method: 'POST',
|
||||
fields: fields,
|
||||
title: '{% trans "Duplicate Supplier Part" %}',
|
||||
@ -260,7 +263,7 @@ function editSupplierPart(part, options={}) {
|
||||
fields.part.hidden = true;
|
||||
}
|
||||
|
||||
constructForm(`/api/company/part/${part}/`, {
|
||||
constructForm(`{% url "api-supplier-part-list" %}${part}/`, {
|
||||
fields: fields,
|
||||
title: options.title || '{% trans "Edit Supplier Part" %}',
|
||||
onSuccess: options.onSuccess
|
||||
@ -443,24 +446,18 @@ function createCompany(options={}) {
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Load company listing data into specified table.
|
||||
*
|
||||
* Args:
|
||||
* - table: Table element on the page
|
||||
* - url: Base URL for the API query
|
||||
* - options: table options.
|
||||
*/
|
||||
function loadCompanyTable(table, url, options={}) {
|
||||
/*
|
||||
* Load company listing data into specified table.
|
||||
*
|
||||
* Args:
|
||||
* - table: Table element on the page
|
||||
* - url: Base URL for the API query
|
||||
* - options: table options.
|
||||
*/
|
||||
|
||||
// Query parameters
|
||||
var params = options.params || {};
|
||||
|
||||
var filters = loadTableFilters('company');
|
||||
|
||||
for (var key in params) {
|
||||
filters[key] = params[key];
|
||||
}
|
||||
let params = options.params || {};
|
||||
let filters = loadTableFilters('company', params);
|
||||
|
||||
setupFilterList('company', $(table));
|
||||
|
||||
@ -547,6 +544,230 @@ function loadCompanyTable(table, url, options={}) {
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Construct a set of form fields for the Contact model
|
||||
*/
|
||||
function contactFields(options={}) {
|
||||
|
||||
let fields = {
|
||||
company: {
|
||||
icon: 'fa-building',
|
||||
},
|
||||
name: {
|
||||
icon: 'fa-user',
|
||||
},
|
||||
phone: {
|
||||
icon: 'fa-phone'
|
||||
},
|
||||
email: {
|
||||
icon: 'fa-at',
|
||||
},
|
||||
role: {
|
||||
icon: 'fa-user-tag',
|
||||
},
|
||||
};
|
||||
|
||||
if (options.company) {
|
||||
fields.company.value = options.company;
|
||||
}
|
||||
|
||||
return fields;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Launches a form to create a new Contact
|
||||
*/
|
||||
function createContact(options={}) {
|
||||
let fields = options.fields || contactFields(options);
|
||||
|
||||
constructForm('{% url "api-contact-list" %}', {
|
||||
method: 'POST',
|
||||
fields: fields,
|
||||
title: '{% trans "Create New Contact" %}',
|
||||
onSuccess: function(response) {
|
||||
handleFormSuccess(response, options);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Launches a form to edit an existing Contact
|
||||
*/
|
||||
function editContact(pk, options={}) {
|
||||
let fields = options.fields || contactFields(options);
|
||||
|
||||
constructForm(`{% url "api-contact-list" %}${pk}/`, {
|
||||
fields: fields,
|
||||
title: '{% trans "Edit Contact" %}',
|
||||
onSuccess: function(response) {
|
||||
handleFormSuccess(response, options);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Launches a form to delete one (or more) contacts
|
||||
*/
|
||||
function deleteContacts(contacts, options={}) {
|
||||
|
||||
if (contacts.length == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
function renderContact(contact) {
|
||||
return `
|
||||
<tr>
|
||||
<td>${contact.name}</td>
|
||||
<td>${contact.email}</td>
|
||||
<td>${contact.role}</td>
|
||||
</tr>`;
|
||||
}
|
||||
|
||||
let rows = '';
|
||||
let ids = [];
|
||||
|
||||
contacts.forEach(function(contact) {
|
||||
rows += renderContact(contact);
|
||||
ids.push(contact.pk);
|
||||
});
|
||||
|
||||
let html = `
|
||||
<div class='alert alert-block alert-danger'>
|
||||
{% trans "All selected contacts will be deleted" %}
|
||||
</div>
|
||||
<table class='table table-striped table-condensed'>
|
||||
<tr>
|
||||
<th>{% trans "Name" %}</th>
|
||||
<th>{% trans "Email" %}</th>
|
||||
<th>{% trans "Role" %}</th>
|
||||
</tr>
|
||||
${rows}
|
||||
</table>`;
|
||||
|
||||
constructForm('{% url "api-contact-list" %}', {
|
||||
method: 'DELETE',
|
||||
multi_delete: true,
|
||||
title: '{% trans "Delete Contacts" %}',
|
||||
preFormContent: html,
|
||||
form_data: {
|
||||
items: ids,
|
||||
},
|
||||
onSuccess: function(response) {
|
||||
handleFormSuccess(response, options);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Load table listing company contacts
|
||||
*/
|
||||
function loadContactTable(table, options={}) {
|
||||
|
||||
var params = options.params || {};
|
||||
|
||||
var filters = loadTableFilters('contact', params);
|
||||
|
||||
setupFilterList('contact', $(table), '#filter-list-contacts');
|
||||
|
||||
$(table).inventreeTable({
|
||||
url: '{% url "api-contact-list" %}',
|
||||
queryParams: filters,
|
||||
original: params,
|
||||
idField: 'pk',
|
||||
uniqueId: 'pk',
|
||||
sidePagination: 'server',
|
||||
formatNoMatches: function() {
|
||||
return '{% trans "No contacts found" %}';
|
||||
},
|
||||
showColumns: true,
|
||||
name: 'contacts',
|
||||
columns: [
|
||||
{
|
||||
field: 'name',
|
||||
title: '{% trans "Name" %}',
|
||||
sortable: true,
|
||||
switchable: false,
|
||||
},
|
||||
{
|
||||
field: 'phone',
|
||||
title: '{% trans "Phone Number" %}',
|
||||
sortable: false,
|
||||
switchable: true,
|
||||
},
|
||||
{
|
||||
field: 'email',
|
||||
title: '{% trans "Email Address" %}',
|
||||
sortable: false,
|
||||
switchable: true,
|
||||
},
|
||||
{
|
||||
field: 'role',
|
||||
title: '{% trans "Role" %}',
|
||||
sortable: false,
|
||||
switchable: false,
|
||||
},
|
||||
{
|
||||
field: 'actions',
|
||||
title: '',
|
||||
sortable: false,
|
||||
switchable: false,
|
||||
visible: options.allow_edit || options.allow_delete,
|
||||
formatter: function(value, row) {
|
||||
var pk = row.pk;
|
||||
|
||||
let html = '';
|
||||
|
||||
if (options.allow_edit) {
|
||||
html += makeEditButton('btn-contact-edit', pk, '{% trans "Edit Contact" %}');
|
||||
}
|
||||
|
||||
if (options.allow_delete) {
|
||||
html += makeDeleteButton('btn-contact-delete', pk, '{% trans "Delete Contact" %}');
|
||||
}
|
||||
|
||||
return wrapButtons(html);
|
||||
}
|
||||
}
|
||||
],
|
||||
onPostBody: function() {
|
||||
// Edit button callback
|
||||
if (options.allow_edit) {
|
||||
$(table).find('.btn-contact-edit').click(function() {
|
||||
var pk = $(this).attr('pk');
|
||||
editContact(pk, {
|
||||
onSuccess: function() {
|
||||
$(table).bootstrapTable('refresh');
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Delete button callback
|
||||
if (options.allow_delete) {
|
||||
$(table).find('.btn-contact-delete').click(function() {
|
||||
var pk = $(this).attr('pk');
|
||||
|
||||
var row = $(table).bootstrapTable('getRowByUniqueId', pk);
|
||||
|
||||
if (row && row.pk) {
|
||||
|
||||
deleteContacts([row], {
|
||||
onSuccess: function() {
|
||||
$(table).bootstrapTable('refresh');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/* Delete one or more ManufacturerPart objects from the database.
|
||||
* - User will be provided with a modal form, showing all the parts to be deleted.
|
||||
* - Delete operations are performed sequentialy, not simultaneously
|
||||
@ -653,21 +874,16 @@ function deleteManufacturerPartParameters(selections, options={}) {
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Load manufacturer part table
|
||||
*/
|
||||
function loadManufacturerPartTable(table, url, options) {
|
||||
/*
|
||||
* Load manufacturer part table
|
||||
*
|
||||
*/
|
||||
|
||||
// Query parameters
|
||||
var params = options.params || {};
|
||||
|
||||
// Load filters
|
||||
var filters = loadTableFilters('manufacturer-part');
|
||||
|
||||
for (var key in params) {
|
||||
filters[key] = params[key];
|
||||
}
|
||||
var filters = loadTableFilters('manufacturer-part', params);
|
||||
|
||||
var filterTarget = options.filterTarget || '#filter-list-manufacturer-part';
|
||||
|
||||
@ -703,11 +919,11 @@ function loadManufacturerPartTable(table, url, options) {
|
||||
var html = imageHoverIcon(row.part_detail.thumbnail) + renderLink(value, url);
|
||||
|
||||
if (row.part_detail.is_template) {
|
||||
html += `<span class='fas fa-clone float-right' title='{% trans "Template part" %}'></span>`;
|
||||
html += makeIconBadge('fa-clone', '{% trans "Template part" %}');
|
||||
}
|
||||
|
||||
if (row.part_detail.assembly) {
|
||||
html += `<span class='fas fa-tools float-right' title='{% trans "Assembled part" %}'></span>`;
|
||||
html += makeIconBadge('fa-tools', '{% trans "Assembled part" %}');
|
||||
}
|
||||
|
||||
if (!row.part_detail.active) {
|
||||
@ -764,16 +980,13 @@ function loadManufacturerPartTable(table, url, options) {
|
||||
sortable: false,
|
||||
switchable: false,
|
||||
formatter: function(value, row) {
|
||||
var pk = row.pk;
|
||||
let pk = row.pk;
|
||||
let html = '';
|
||||
|
||||
var html = `<div class='btn-group float-right' role='group'>`;
|
||||
html += makeEditButton('button-manufacturer-part-edit', pk, '{% trans "Edit manufacturer part" %}');
|
||||
html += makeDeleteButton('button-manufacturer-part-delete', pk, '{% trans "Delete manufacturer part" %}');
|
||||
|
||||
html += makeIconButton('fa-edit icon-blue', 'button-manufacturer-part-edit', pk, '{% trans "Edit manufacturer part" %}');
|
||||
html += makeIconButton('fa-trash-alt icon-red', 'button-manufacturer-part-delete', pk, '{% trans "Delete manufacturer part" %}');
|
||||
|
||||
html += '</div>';
|
||||
|
||||
return html;
|
||||
return wrapButtons(html);
|
||||
}
|
||||
}
|
||||
],
|
||||
@ -810,20 +1023,15 @@ function loadManufacturerPartTable(table, url, options) {
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Load table of ManufacturerPartParameter objects
|
||||
*/
|
||||
function loadManufacturerPartParameterTable(table, url, options) {
|
||||
/*
|
||||
* Load table of ManufacturerPartParameter objects
|
||||
*/
|
||||
|
||||
var params = options.params || {};
|
||||
|
||||
// Load filters
|
||||
var filters = loadTableFilters('manufacturer-part-parameters');
|
||||
|
||||
// Overwrite explicit parameters
|
||||
for (var key in params) {
|
||||
filters[key] = params[key];
|
||||
}
|
||||
var filters = loadTableFilters('manufacturer-part-parameters', params);
|
||||
|
||||
setupFilterList('manufacturer-part-parameters', $(table));
|
||||
|
||||
@ -867,17 +1075,13 @@ function loadManufacturerPartParameterTable(table, url, options) {
|
||||
switchable: false,
|
||||
sortable: false,
|
||||
formatter: function(value, row) {
|
||||
let pk = row.pk;
|
||||
let html = '';
|
||||
|
||||
var pk = row.pk;
|
||||
html += makeEditButton('button-parameter-edit', pk, '{% trans "Edit parameter" %}');
|
||||
html += makeDeleteButton('button-parameter-delete', pk, '{% trans "Delete parameter" %}');
|
||||
|
||||
var html = `<div class='btn-group float-right' role='group'>`;
|
||||
|
||||
html += makeIconButton('fa-edit icon-blue', 'button-parameter-edit', pk, '{% trans "Edit parameter" %}');
|
||||
html += makeIconButton('fa-trash-alt icon-red', 'button-parameter-delete', pk, '{% trans "Delete parameter" %}');
|
||||
|
||||
html += `</div>`;
|
||||
|
||||
return html;
|
||||
return wrapButtons(html);
|
||||
}
|
||||
}
|
||||
],
|
||||
@ -886,27 +1090,23 @@ function loadManufacturerPartParameterTable(table, url, options) {
|
||||
$(table).find('.button-parameter-edit').click(function() {
|
||||
var pk = $(this).attr('pk');
|
||||
|
||||
constructForm(`/api/company/part/manufacturer/parameter/${pk}/`, {
|
||||
constructForm(`{% url "api-manufacturer-part-parameter-list" %}${pk}/`, {
|
||||
fields: {
|
||||
name: {},
|
||||
value: {},
|
||||
units: {},
|
||||
},
|
||||
title: '{% trans "Edit Parameter" %}',
|
||||
onSuccess: function() {
|
||||
$(table).bootstrapTable('refresh');
|
||||
}
|
||||
refreshTable: table,
|
||||
});
|
||||
});
|
||||
$(table).find('.button-parameter-delete').click(function() {
|
||||
var pk = $(this).attr('pk');
|
||||
|
||||
constructForm(`/api/company/part/manufacturer/parameter/${pk}/`, {
|
||||
constructForm(`{% url "api-manufacturer-part-parameter-list" %}${pk}/`, {
|
||||
method: 'DELETE',
|
||||
title: '{% trans "Delete Parameter" %}',
|
||||
onSuccess: function() {
|
||||
$(table).bootstrapTable('refresh');
|
||||
}
|
||||
refreshTable: table,
|
||||
});
|
||||
});
|
||||
}
|
||||
@ -914,21 +1114,16 @@ function loadManufacturerPartParameterTable(table, url, options) {
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Load supplier part table
|
||||
*/
|
||||
function loadSupplierPartTable(table, url, options) {
|
||||
/*
|
||||
* Load supplier part table
|
||||
*
|
||||
*/
|
||||
|
||||
// Query parameters
|
||||
var params = options.params || {};
|
||||
|
||||
// Load filters
|
||||
var filters = loadTableFilters('supplier-part');
|
||||
|
||||
for (var key in params) {
|
||||
filters[key] = params[key];
|
||||
}
|
||||
var filters = loadTableFilters('supplier-part', params);
|
||||
|
||||
setupFilterList('supplier-part', $(table));
|
||||
|
||||
@ -964,11 +1159,11 @@ function loadSupplierPartTable(table, url, options) {
|
||||
var html = imageHoverIcon(row.part_detail.thumbnail) + renderLink(value, url);
|
||||
|
||||
if (row.part_detail.is_template) {
|
||||
html += `<span class='fas fa-clone float-right' title='{% trans "Template part" %}'></span>`;
|
||||
html += makeIconBadge('fa-clone', '{% trans "Template part" %}');
|
||||
}
|
||||
|
||||
if (row.part_detail.assembly) {
|
||||
html += `<span class='fas fa-tools float-right' title='{% trans "Assembled part" %}'></span>`;
|
||||
html += makeIconBadge('fa-tools', '{% trans "Assembled part" %}');
|
||||
}
|
||||
|
||||
if (!row.part_detail.active) {
|
||||
@ -1088,9 +1283,13 @@ function loadSupplierPartTable(table, url, options) {
|
||||
sortable: true,
|
||||
formatter: function(value, row) {
|
||||
if (row.availability_updated) {
|
||||
var html = formatDecimal(value);
|
||||
var date = renderDate(row.availability_updated, {showTime: true});
|
||||
html += `<span class='fas fa-info-circle float-right' title='{% trans "Last Updated" %}: ${date}'></span>`;
|
||||
let html = formatDecimal(value);
|
||||
let date = renderDate(row.availability_updated, {showTime: true});
|
||||
|
||||
html += makeIconBadge(
|
||||
'fa-info-circle',
|
||||
`{% trans "Last Updated" %}: ${date}`
|
||||
);
|
||||
return html;
|
||||
} else {
|
||||
return '-';
|
||||
@ -1108,16 +1307,13 @@ function loadSupplierPartTable(table, url, options) {
|
||||
sortable: false,
|
||||
switchable: false,
|
||||
formatter: function(value, row) {
|
||||
var pk = row.pk;
|
||||
let pk = row.pk;
|
||||
let html = '';
|
||||
|
||||
var html = `<div class='btn-group float-right' role='group'>`;
|
||||
html += makeEditButton('button-supplier-part-edit', pk, '{% trans "Edit supplier part" %}');
|
||||
html += makeDeleteButton('button-supplier-part-delete', pk, '{% trans "Delete supplier part" %}');
|
||||
|
||||
html += makeIconButton('fa-edit icon-blue', 'button-supplier-part-edit', pk, '{% trans "Edit supplier part" %}');
|
||||
html += makeIconButton('fa-trash-alt icon-red', 'button-supplier-part-delete', pk, '{% trans "Delete supplier part" %}');
|
||||
|
||||
html += '</div>';
|
||||
|
||||
return html;
|
||||
return wrapButtons(html);
|
||||
}
|
||||
}
|
||||
],
|
||||
@ -1166,24 +1362,20 @@ function loadSupplierPriceBreakTable(options={}) {
|
||||
table.find('.button-price-break-delete').click(function() {
|
||||
var pk = $(this).attr('pk');
|
||||
|
||||
constructForm(`/api/company/price-break/${pk}/`, {
|
||||
constructForm(`{% url "api-part-supplier-price-list" %}${pk}/`, {
|
||||
method: 'DELETE',
|
||||
title: '{% trans "Delete Price Break" %}',
|
||||
onSuccess: function() {
|
||||
table.bootstrapTable('refresh');
|
||||
},
|
||||
refreshTable: table,
|
||||
});
|
||||
});
|
||||
|
||||
table.find('.button-price-break-edit').click(function() {
|
||||
var pk = $(this).attr('pk');
|
||||
|
||||
constructForm(`/api/company/price-break/${pk}/`, {
|
||||
constructForm(`{% url "api-part-supplier-price-list" %}${pk}/`, {
|
||||
fields: supplierPartPriceBreakFields(),
|
||||
title: '{% trans "Edit Price Break" %}',
|
||||
onSuccess: function() {
|
||||
table.bootstrapTable('refresh');
|
||||
}
|
||||
refreshTable: table,
|
||||
});
|
||||
});
|
||||
}
|
||||
@ -1231,10 +1423,12 @@ function loadSupplierPriceBreakTable(options={}) {
|
||||
formatter: function(value, row) {
|
||||
var html = renderDate(value);
|
||||
|
||||
html += `<div class='btn-group float-right' role='group'>`;
|
||||
html += makeIconButton('fa-edit icon-blue', 'button-price-break-edit', row.pk, '{% trans "Edit price break" %}');
|
||||
html += makeIconButton('fa-trash-alt icon-red', 'button-price-break-delete', row.pk, '{% trans "Delete price break" %}');
|
||||
html += `</div>`;
|
||||
let buttons = '';
|
||||
|
||||
buttons += makeEditButton('button-price-break-edit', row.pk, '{% trans "Edit price break" %}');
|
||||
buttons += makeDeleteButton('button-price-break-delete', row.pk, '{% trans "Delete price break" %}');
|
||||
|
||||
html += wrapButtons(buttons);
|
||||
|
||||
return html;
|
||||
}
|
||||
|
Reference in New Issue
Block a user