Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ jobs:
strategy:
max-parallel: 4
matrix:
python-version: [3.9]
python-version: [3.11]

steps:
- name: Checkout Code
Expand Down
45 changes: 42 additions & 3 deletions inventree/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

from . import api as inventree_api

INVENTREE_PYTHON_VERSION = "0.19.0"
INVENTREE_PYTHON_VERSION = "0.20.0"


logger = logging.getLogger('inventree')
Expand Down Expand Up @@ -506,13 +506,14 @@ def download(self, destination, **kwargs):
class AttachmentMixin:
"""Mixin class which allows a model class to interact with attachments."""

def getAttachments(self):
def getAttachments(self, **kwargs):
"""Return a list of attachments associated with this object."""

return Attachment.list(
self._api,
model_type=self.getModelType(),
model_id=self.pk
model_id=self.pk,
**kwargs
)

def uploadAttachment(self, attachment, comment=""):
Expand Down Expand Up @@ -543,6 +544,44 @@ def addLinkAttachment(self, link, comment=""):
)


class Parameter(BulkDeleteMixin, InventreeObject):
"""Class representing a custom parameter object."""

URL = "parameter/"

# Ref: https://github.com/inventree/InvenTree/pull/10699
MIN_API_VERSION = 429


class ParameterTemplate(InventreeObject):
"""Class representing a parameter template object."""

URL = "parameter/template/"

# Ref: https://github.com/inventree/InvenTree/pull/10699
MIN_API_VERSION = 429


class ParameterMixin:
"""Mixin class which allows a model class to interact with parameters.

Ref: https://github.com/inventree/InvenTree/pull/10699
"""

def getParameters(self, **kwargs):
"""Return a list of parameters associated with this object."""

if self._api.api_version < Parameter.MIN_API_VERSION:
raise NotImplementedError(f"Server API Version ({self._api.api_version}) is too old for ParameterMixin, which requires API version >= {Parameter.MIN_API_VERSION}")

return Parameter.list(
self._api,
model_type=self.getModelType(),
model_id=self.pk,
**kwargs
)


class MetadataMixin:
"""Mixin class for models which support a 'metadata' attribute.

Expand Down
1 change: 1 addition & 0 deletions inventree/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

class Build(
inventree.base.AttachmentMixin,
inventree.base.ParameterMixin,
inventree.base.StatusMixin,
inventree.base.MetadataMixin,
inventree.report.ReportPrintingMixin,
Expand Down
28 changes: 24 additions & 4 deletions inventree/company.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,13 @@ class Address(inventree.base.InventreeObject):
MIN_API_VERSION = 126


class Company(inventree.base.ImageMixin, inventree.base.MetadataMixin, inventree.base.InventreeObject):
class Company(
inventree.base.AttachmentMixin,
inventree.base.ParameterMixin,
inventree.base.ImageMixin,
inventree.base.MetadataMixin,
inventree.base.InventreeObject
):
""" Class representing the Company database model """

URL = 'company/'
Expand Down Expand Up @@ -97,7 +103,14 @@ def createReturnOrder(self, **kwargs):
return inventree.order.ReturnOrder.create(self._api, data=kwargs)


class SupplierPart(inventree.base.BarcodeMixin, inventree.base.BulkDeleteMixin, inventree.base.MetadataMixin, inventree.base.InventreeObject):
class SupplierPart(
inventree.base.AttachmentMixin,
inventree.base.ParameterMixin,
inventree.base.BarcodeMixin,
inventree.base.BulkDeleteMixin,
inventree.base.MetadataMixin,
inventree.base.InventreeObject
):
"""Class representing the SupplierPart database model

- Implements the BulkDeleteMixin
Expand All @@ -113,6 +126,7 @@ def getPriceBreaks(self):

class ManufacturerPart(
inventree.base.AttachmentMixin,
inventree.base.ParameterMixin,
inventree.base.BulkDeleteMixin,
inventree.base.MetadataMixin,
inventree.base.InventreeObject,
Expand All @@ -130,16 +144,22 @@ def getParameters(self, **kwargs):
GET a list of all ManufacturerPartParameter objects for this ManufacturerPart
"""

return ManufacturerPartParameter.list(self._api, manufacturer_part=self.pk, **kwargs)
# Support legacy API version which uses a different endpoint
if self._api.api_version < inventree.base.Parameter.MIN_API_VERSION:
return ManufacturerPartParameter.list(self._api, manufacturer_part=self.pk, **kwargs)

return super().getParameters(**kwargs)


class ManufacturerPartParameter(inventree.base.BulkDeleteMixin, inventree.base.InventreeObject):
"""Class representing the ManufacturerPartParameter database model.

- Implements the BulkDeleteMixin
Note: This class was removed in API version 418 and later.
Ref: https://github.com/inventree/InvenTree/pull/10699
"""

URL = 'company/part/manufacturer/parameter/'
MAX_API_VERSION = 428


class SupplierPriceBreak(inventree.base.InventreeObject):
Expand Down
38 changes: 32 additions & 6 deletions inventree/part.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,14 @@ def getCategory(self):

def getTemplate(self):
"""Return the referenced ParameterTemplate instance"""
return ParameterTemplate(self._api, self.parameter_template)

template_id = getattr(self, 'template', None) or getattr(self, 'parameter_template', None)

if self._api.api_version < inventree.base.ParameterTemplate.MIN_API_VERSION:
# Return legacy PartParameterTemplate object
return PartParameterTemplate(self._api, template_id)

return inventree.base.ParameterTemplate(self._api, template_id)


class PartCategory(inventree.base.MetadataMixin, inventree.base.InventreeObject):
Expand Down Expand Up @@ -60,6 +67,7 @@ def getCategoryParameterTemplates(self, fetch_parent: bool = True) -> list:

class Part(
inventree.base.AttachmentMixin,
inventree.base.ParameterMixin,
inventree.base.BarcodeMixin,
inventree.base.MetadataMixin,
inventree.base.ImageMixin,
Expand Down Expand Up @@ -108,7 +116,12 @@ def getStockItems(self, **kwargs):

def getParameters(self):
""" Return parameters associated with this part """
return Parameter.list(self._api, part=self.pk)

if self._api.api_version < inventree.base.Parameter.MIN_API_VERSION:
# Return legacy PartParameter objects
return PartParameter.list(self._api, part=self.pk)

return super().getParameters()

def getRelated(self):
""" Return related parts associated with this part """
Expand Down Expand Up @@ -264,17 +277,30 @@ def add_related(cls, api, part1, part2):
return api.post(cls.URL, data)


class Parameter(inventree.base.InventreeObject):
"""class representing the Parameter database model """
class PartParameter(inventree.base.InventreeObject):
"""Legacy class representing the PartParameter database model.

This has now been replaced with the generic Parameter model.

Ref: https://github.com/inventree/InvenTree/pull/10699
"""
URL = 'part/parameter/'

MAX_API_VERSION = 428

def getunits(self):
""" Get the units for this parameter """

return self._data['template_detail']['units']


class ParameterTemplate(inventree.base.InventreeObject):
""" class representing the Parameter Template database model"""
class PartParameterTemplate(inventree.base.InventreeObject):
"""Legacy class representing the PartParameterTemplate database model.

This has now been replaced with the generic ParameterTemplate model.

Ref: https://github.com/inventree/InvenTree/pull/10699
"""

URL = 'part/parameter/template/'
MAX_API_VERSION = 428
1 change: 1 addition & 0 deletions inventree/purchase_order.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

class PurchaseOrder(
inventree.base.AttachmentMixin,
inventree.base.ParameterMixin,
inventree.base.MetadataMixin,
inventree.base.StatusMixin,
inventree.report.ReportPrintingMixin,
Expand Down
1 change: 1 addition & 0 deletions inventree/return_order.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

class ReturnOrder(
inventree.base.AttachmentMixin,
inventree.base.ParameterMixin,
inventree.base.MetadataMixin,
inventree.base.StatusMixin,
inventree.report.ReportPrintingMixin,
Expand Down
1 change: 1 addition & 0 deletions inventree/sales_order.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

class SalesOrder(
inventree.base.AttachmentMixin,
inventree.base.ParameterMixin,
inventree.base.MetadataMixin,
inventree.base.StatusMixin,
inventree.report.ReportPrintingMixin,
Expand Down
2 changes: 1 addition & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@ ignore =
# - E501 - line too long (82 characters)
E501
N802
exclude = .git,__pycache__,inventree_server,dist,build,test.py
exclude = .git,.eggs,__pycache__,inventree_server,dist,build,test.py
max-complexity = 20
73 changes: 0 additions & 73 deletions test/test_company.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@
import os
import sys

from requests.exceptions import HTTPError

try:
import Image
except ImportError:
Expand Down Expand Up @@ -127,77 +125,6 @@ def test_manufacturer_part_create(self):
man_parts = company.ManufacturerPart.list(self.api, manufacturer=manufacturer.pk)
self.assertEqual(len(man_parts), n + 1)

def test_manufacturer_part_parameters(self):
"""
Test that we can create, retrieve and edit ManufacturerPartParameter objects
"""

n = len(company.ManufacturerPart.list(self.api))

mpn = f"XYZ-12345678-{n}"

# First, create a new ManufacturerPart
part = company.ManufacturerPart.create(self.api, {
'manufacturer': 6,
'part': 1,
'MPN': mpn,
})

self.assertIsNotNone(part)
self.assertEqual(len(company.ManufacturerPart.list(self.api)), n + 1)

# Part should (initially) not have any parameters
self.assertEqual(len(part.getParameters()), 0)

# Now, let's create some!
for idx in range(10):

parameter = company.ManufacturerPartParameter.create(self.api, {
'manufacturer_part': part.pk,
'name': f"param {idx}",
'value': f"{idx}",
})

self.assertIsNotNone(parameter)

# Now should have 10 unique parameters
self.assertEqual(len(part.getParameters()), 10)

# Attempt to create a duplicate parameter
with self.assertRaises(HTTPError):
company.ManufacturerPartParameter.create(self.api, {
'manufacturer_part': part.pk,
'name': 'param 0',
'value': 'some value',
})

self.assertEqual(len(part.getParameters()), 10)

# Test that we can edit a ManufacturerPartParameter
parameter = part.getParameters()[0]

self.assertEqual(parameter.value, '0')

parameter['value'] = 'new value'
parameter.save()

self.assertEqual(parameter.value, 'new value')

parameter['value'] = 'dummy value'
parameter.reload()

self.assertEqual(parameter.value, 'new value')

# Test that the "list" function works correctly
results = company.ManufacturerPartParameter.list(self.api)
self.assertGreaterEqual(len(results), 10)

results = company.ManufacturerPartParameter.list(self.api, name='param 1')
self.assertGreaterEqual(len(results), 1)

results = company.ManufacturerPartParameter.list(self.api, manufacturer_part=part.pk)
self.assertGreaterEqual(len(results), 10)

def test_supplier_part_create(self):
"""
Test that we can create SupplierPart objects via the API
Expand Down
Loading