diff --git a/src/backend/InvenTree/InvenTree/api_version.py b/src/backend/InvenTree/InvenTree/api_version.py index 6e436a5df0..91497f5ec7 100644 --- a/src/backend/InvenTree/InvenTree/api_version.py +++ b/src/backend/InvenTree/InvenTree/api_version.py @@ -1,12 +1,15 @@ """InvenTree API version information.""" # InvenTree API version -INVENTREE_API_VERSION = 223 +INVENTREE_API_VERSION = 224 """Increment this API version number whenever there is a significant change to the API that any clients need to know about.""" INVENTREE_API_TEXT = """ +v224 - 2024-07-14 : https://github.com/inventree/InvenTree/pull/7667 + - Add notes field to ManufacturerPart and SupplierPart API endpoints + v223 - 2024-07-14 : https://github.com/inventree/InvenTree/pull/7649 - Allow adjustment of "packaging" field when receiving items against a purchase order diff --git a/src/backend/InvenTree/company/migrations/0071_manufacturerpart_notes_supplierpart_notes.py b/src/backend/InvenTree/company/migrations/0071_manufacturerpart_notes_supplierpart_notes.py new file mode 100644 index 0000000000..b7d6c8caf7 --- /dev/null +++ b/src/backend/InvenTree/company/migrations/0071_manufacturerpart_notes_supplierpart_notes.py @@ -0,0 +1,24 @@ +# Generated by Django 4.2.11 on 2024-07-16 12:58 + +import InvenTree.fields +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('company', '0070_remove_manufacturerpartattachment_manufacturer_part_and_more'), + ] + + operations = [ + migrations.AddField( + model_name='manufacturerpart', + name='notes', + field=InvenTree.fields.InvenTreeNotesField(blank=True, help_text='Markdown notes (optional)', max_length=50000, null=True, verbose_name='Notes'), + ), + migrations.AddField( + model_name='supplierpart', + name='notes', + field=InvenTree.fields.InvenTreeNotesField(blank=True, help_text='Markdown notes (optional)', max_length=50000, null=True, verbose_name='Notes'), + ), + ] diff --git a/src/backend/InvenTree/company/models.py b/src/backend/InvenTree/company/models.py index 58b0938568..52eeb80cdc 100644 --- a/src/backend/InvenTree/company/models.py +++ b/src/backend/InvenTree/company/models.py @@ -451,6 +451,7 @@ class Address(InvenTree.models.InvenTreeModel): class ManufacturerPart( InvenTree.models.InvenTreeAttachmentMixin, InvenTree.models.InvenTreeBarcodeMixin, + InvenTree.models.InvenTreeNotesMixin, InvenTree.models.InvenTreeMetadataModel, ): """Represents a unique part as provided by a Manufacturer Each ManufacturerPart is identified by a MPN (Manufacturer Part Number) Each ManufacturerPart is also linked to a Part object. A Part may be available from multiple manufacturers. @@ -624,6 +625,7 @@ class SupplierPartManager(models.Manager): class SupplierPart( InvenTree.models.MetadataMixin, InvenTree.models.InvenTreeBarcodeMixin, + InvenTree.models.InvenTreeNotesMixin, common.models.MetaMixin, InvenTree.models.InvenTreeModel, ): diff --git a/src/backend/InvenTree/company/serializers.py b/src/backend/InvenTree/company/serializers.py index 68597d60a7..428ea7b5b8 100644 --- a/src/backend/InvenTree/company/serializers.py +++ b/src/backend/InvenTree/company/serializers.py @@ -213,7 +213,7 @@ class ContactSerializer(DataImportExportSerializerMixin, InvenTreeModelSerialize @register_importer() class ManufacturerPartSerializer( - DataImportExportSerializerMixin, InvenTreeTagModelSerializer + DataImportExportSerializerMixin, InvenTreeTagModelSerializer, NotesFieldMixin ): """Serializer for ManufacturerPart object.""" @@ -232,6 +232,7 @@ class ManufacturerPartSerializer( 'MPN', 'link', 'barcode_hash', + 'notes', 'tags', ] @@ -305,7 +306,7 @@ class ManufacturerPartParameterSerializer( @register_importer() class SupplierPartSerializer( - DataImportExportSerializerMixin, InvenTreeTagModelSerializer + DataImportExportSerializerMixin, InvenTreeTagModelSerializer, NotesFieldMixin ): """Serializer for SupplierPart object.""" @@ -340,6 +341,7 @@ class SupplierPartSerializer( 'supplier_detail', 'url', 'updated', + 'notes', 'tags', ] diff --git a/src/backend/InvenTree/company/templates/company/manufacturer_part.html b/src/backend/InvenTree/company/templates/company/manufacturer_part.html index a4676a9086..7d07fe282e 100644 --- a/src/backend/InvenTree/company/templates/company/manufacturer_part.html +++ b/src/backend/InvenTree/company/templates/company/manufacturer_part.html @@ -171,11 +171,40 @@ src="{% static 'img/blank_image.png' %}" +
+
+
+

{% trans "Manufacturer Part Notes" %}

+ {% include "spacer.html" %} +
+ {% include "notes_buttons.html" %} +
+
+
+
+ +
+
+ {% endblock page_content %} {% block js_ready %} {{ block.super }} +// Load the "notes" tab +onPanelLoad('manufacturer-part-notes', function() { + + setupNotesField( + 'manufacturer-part-notes', + '{% url "api-manufacturer-part-detail" part.pk %}', + { + model_type: "manufacturerpart", + model_id: {{ part.pk }}, + editable: {% js_bool roles.purchase_order.change %}, + } + ); +}); + onPanelLoad("attachments", function() { loadAttachmentTable('manufacturerpart', {{ part.pk }}); }); diff --git a/src/backend/InvenTree/company/templates/company/manufacturer_part_sidebar.html b/src/backend/InvenTree/company/templates/company/manufacturer_part_sidebar.html index 64f8f950b0..fb538cb290 100644 --- a/src/backend/InvenTree/company/templates/company/manufacturer_part_sidebar.html +++ b/src/backend/InvenTree/company/templates/company/manufacturer_part_sidebar.html @@ -8,3 +8,5 @@ {% include "sidebar_item.html" with label='supplier-parts' text=text icon="fa-building" %} {% trans "Attachments" as text %} {% include "sidebar_item.html" with label='attachments' text=text icon="fa-paperclip" %} +{% trans "Notes" as text %} +{% include "sidebar_item.html" with label="manufacturer-part-notes" text=text icon="fa-clipboard" %} diff --git a/src/backend/InvenTree/company/templates/company/supplier_part.html b/src/backend/InvenTree/company/templates/company/supplier_part.html index 2949926cb7..16841c5570 100644 --- a/src/backend/InvenTree/company/templates/company/supplier_part.html +++ b/src/backend/InvenTree/company/templates/company/supplier_part.html @@ -264,11 +264,40 @@ src="{% static 'img/blank_image.png' %}" +
+
+
+

{% trans "Supplier Part Notes" %}

+ {% include "spacer.html" %} +
+ {% include "notes_buttons.html" %} +
+
+
+
+ +
+
+ {% endblock page_content %} {% block js_ready %} {{ block.super }} +// Load the "notes" tab +onPanelLoad('supplier-part-notes', function() { + + setupNotesField( + 'supplier-part-notes', + '{% url "api-supplier-part-detail" part.pk %}', + { + model_type: "supplierpart", + model_id: {{ part.pk }}, + editable: {% js_bool roles.purchase_order.change %}, + } + ); +}); + {% if barcodes %} $("#show-qr-code").click(function() { diff --git a/src/backend/InvenTree/company/templates/company/supplier_part_sidebar.html b/src/backend/InvenTree/company/templates/company/supplier_part_sidebar.html index 91c0682e00..d6cd017500 100644 --- a/src/backend/InvenTree/company/templates/company/supplier_part_sidebar.html +++ b/src/backend/InvenTree/company/templates/company/supplier_part_sidebar.html @@ -8,3 +8,5 @@ {% include "sidebar_item.html" with label='purchase-orders' text=text icon="fa-shopping-cart" %} {% trans "Supplier Part Pricing" as text %} {% include "sidebar_item.html" with label='pricing' text=text icon="fa-dollar-sign" %} +{% trans "Notes" as text %} +{% include "sidebar_item.html" with label="supplier-part-notes" text=text icon="fa-clipboard" %} diff --git a/src/frontend/src/pages/company/ManufacturerPartDetail.tsx b/src/frontend/src/pages/company/ManufacturerPartDetail.tsx index 49a8681064..5e5e5f2ba9 100644 --- a/src/frontend/src/pages/company/ManufacturerPartDetail.tsx +++ b/src/frontend/src/pages/company/ManufacturerPartDetail.tsx @@ -5,6 +5,7 @@ import { IconDots, IconInfoCircle, IconList, + IconNotes, IconPaperclip } from '@tabler/icons-react'; import { useMemo } from 'react'; @@ -14,6 +15,7 @@ import AdminButton from '../../components/buttons/AdminButton'; import { DetailsField, DetailsTable } from '../../components/details/Details'; import { DetailsImage } from '../../components/details/DetailsImage'; import { ItemDetailsGrid } from '../../components/details/ItemDetails'; +import NotesEditor from '../../components/editors/NotesEditor'; import { ActionDropdown, DeleteItemAction, @@ -179,6 +181,18 @@ export default function ManufacturerPartDetail() { model_id={manufacturerPart?.pk} /> ) + }, + { + name: 'notes', + label: t`Notes`, + icon: , + content: ( + + ) } ]; }, [manufacturerPart]); diff --git a/src/frontend/src/pages/company/SupplierPartDetail.tsx b/src/frontend/src/pages/company/SupplierPartDetail.tsx index d6e917e21e..1746c4bb9b 100644 --- a/src/frontend/src/pages/company/SupplierPartDetail.tsx +++ b/src/frontend/src/pages/company/SupplierPartDetail.tsx @@ -4,6 +4,7 @@ import { IconCurrencyDollar, IconDots, IconInfoCircle, + IconNotes, IconPackages, IconShoppingCart } from '@tabler/icons-react'; @@ -15,6 +16,7 @@ import { DetailsField, DetailsTable } from '../../components/details/Details'; import DetailsBadge from '../../components/details/DetailsBadge'; import { DetailsImage } from '../../components/details/DetailsImage'; import { ItemDetailsGrid } from '../../components/details/ItemDetails'; +import NotesEditor from '../../components/editors/NotesEditor'; import { ActionDropdown, DeleteItemAction, @@ -240,6 +242,18 @@ export default function SupplierPartDetail() { ) : ( ) + }, + { + name: 'notes', + label: t`Notes`, + icon: , + content: ( + + ) } ]; }, [supplierPart]);