diff --git a/InvenTree/company/templates/company/detail.html b/InvenTree/company/templates/company/detail.html index 49780c56ff..f9094b89f3 100644 --- a/InvenTree/company/templates/company/detail.html +++ b/InvenTree/company/templates/company/detail.html @@ -1,6 +1,7 @@ {% extends "company/company_base.html" %} {% load static %} {% load i18n %} +{% load inventree_extras %} {% block sidebar %} {% include 'company/sidebar.html' %} @@ -163,6 +164,7 @@ +{% if company.is_customer %}

{% trans "Assigned Stock" %}

@@ -175,9 +177,9 @@
-
+{% endif %}
@@ -194,6 +196,31 @@
+
+
+
+

{% trans "Company Contacts" %}

+ {% include "spacer.html" %} +
+ {% if roles.purchase_order.add or roles.sales_order.add %} + + {% endif %} +
+
+
+
+
+
+ {% include "filter_list.html" with id="contacts" %} +
+
+ +
+
+
+
@@ -242,6 +269,27 @@ ); }); + // Callback function when the 'contacts' panel is loaded + onPanelLoad('company-contacts', function() { + loadContactTable('#contacts-table', { + params: { + company: {{ company.pk }}, + }, + allow_edit: {% js_bool roles.purchase_order.change %} || {% js_bool roles.sales_order.change %}, + allow_delete: {% js_bool roles.purchase_order.delete %} || {% js_bool roles.sales_order.delete %}, + }); + + $('#new-contact').click(function() { + createContact({ + company: {{ company.pk }}, + onSuccess: function() { + $('#contacts-table').bootstrapTable('refresh'); + } + }); + }); + }); + + // Callback function when the 'notes' panel is loaded onPanelLoad('company-notes', function() { setupNotesField( @@ -250,19 +298,24 @@ { editable: true, } - ) + ); }); - loadStockTable($("#assigned-stock-table"), { - params: { - customer: {{ company.id }}, - part_detail: true, - location_detail: true, - }, - url: "{% url 'api-stock-list' %}", - filterKey: "customerstock", - filterTarget: '#filter-list-customerstock', + {% if company.is_customer %} + // Callback function when the 'assigned stock' panel is loaded + onPanelLoad('assigned-stock', function() { + loadStockTable($("#assigned-stock-table"), { + params: { + customer: {{ company.id }}, + part_detail: true, + location_detail: true, + }, + url: "{% url 'api-stock-list' %}", + filterKey: "customerstock", + filterTarget: '#filter-list-customerstock', + }); }); + {% endif %} onPanelLoad('company-stock', function() { diff --git a/InvenTree/company/templates/company/sidebar.html b/InvenTree/company/templates/company/sidebar.html index ad40c03a0b..0280f2b5b9 100644 --- a/InvenTree/company/templates/company/sidebar.html +++ b/InvenTree/company/templates/company/sidebar.html @@ -22,6 +22,8 @@ {% trans "Assigned Stock Items" as text %} {% include "sidebar_item.html" with label='assigned-stock' text=text icon="fa-sign-out-alt" %} {% endif %} +{% trans "Contacts" as text %} +{% include "sidebar_item.html" with label='company-contacts' text=text icon="fa-users" %} {% trans "Notes" as text %} {% include "sidebar_item.html" with label='company-notes' text=text icon="fa-clipboard" %} {% trans "Attachments" as text %} diff --git a/InvenTree/templates/js/translated/company.js b/InvenTree/templates/js/translated/company.js index c1ae9ba0d4..5f86f65f91 100644 --- a/InvenTree/templates/js/translated/company.js +++ b/InvenTree/templates/js/translated/company.js @@ -11,16 +11,20 @@ /* exported createCompany, + createContact, createManufacturerPart, createSupplierPart, createSupplierPartPriceBreak, + deleteContacts, deleteManufacturerParts, deleteManufacturerPartParameters, deleteSupplierParts, duplicateSupplierPart, editCompany, + editContact, editSupplierPartPriceBreak, loadCompanyTable, + loadContactTable, loadManufacturerPartTable, loadManufacturerPartParameterTable, loadSupplierPartTable, @@ -443,15 +447,15 @@ 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 || {}; @@ -547,6 +551,234 @@ 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(`/api/company/contact/${pk}/`, { + fields: fields, + title: '{% trans "Edit Contact" %}', + onSuccess: function(response) { + handleFormSuccess(respnose, options); + } + }); +} + + +/* + * Launches a form to delete one (or more) contacts + */ +function deleteContacts(contacts, options={}) { + + if (contacts.length == 0) { + return; + } + + function renderContact(contact) { + return ` + + ${contact.name} + ${contact.email} + ${contact.role} + `; + } + + let rows = ''; + let ids = []; + + contacts.forEach(function(contact) { + rows += renderContact(contact); + ids.push(contact.pk); + }); + + let html = ` +
+ {% trans "All selected contacts will be deleted" %} +
+ + + + + + + ${rows} +
{% trans "Name" %}{% trans "Email" %}{% trans "Role" %}
`; + + 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'); + + for (var key in params) { + filters[key] = params[key]; + } + + 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; + + var html = `
`; + if (options.allow_edit) { + html += makeIconButton('fa-edit icon-blue', 'btn-contact-edit', pk, '{% trans "Edit Contact" %}'); + } + + if (options.allow_delete) { + html += makeIconButton('fa-trash-alt icon-red', 'btn-contact-delete', pk, '{% trans "Delete Contact" %}'); + } + + html += '
'; + return 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