mirror of
				https://github.com/inventree/InvenTree.git
				synced 2025-10-31 05:05:42 +00:00 
			
		
		
		
	Docstring checks in QC checks (#3089)
* Add pre-commit to the stack * exclude static * Add locales to excludes * fix style errors * rename pipeline steps * also wait on precommit * make template matching simpler * Use the same code for python setup everywhere * use step and cache for python setup * move regular settings up into general envs * just use full update * Use invoke instead of static references * make setup actions more similar * use python3 * refactor names to be similar * fix runner version * fix references * remove incidential change * use matrix for os * Github can't do this right now * ignore docstyle errors * Add seperate docstring test * update flake call * do not fail on docstring * refactor setup into workflow * update reference * switch to action * resturcture * add bash statements * remove os from cache * update input checks * make code cleaner * fix boolean * no relative paths * install wheel by python * switch to install * revert back to simple wheel * refactor import export tests * move setup keys back to not disturbe tests * remove docstyle till that is fixed * update references * continue on error * add docstring test * use relativ action references * Change step / job docstrings * update to merge * reformat comments 1 * fix docstrings 2 * fix docstrings 3 * fix docstrings 4 * fix docstrings 5 * fix docstrings 6 * fix docstrings 7 * fix docstrings 8 * fix docstirns 9 * fix docstrings 10 * docstring adjustments * update the remaining docstrings * small docstring changes * fix function name * update support files for docstrings * Add missing args to docstrings * Remove outdated function * Add docstrings for the 'build' app * Make API code cleaner * add more docstrings for plugin app * Remove dead code for plugin settings No idea what that was even intended for * ignore __init__ files for docstrings * More docstrings * Update docstrings for the 'part' directory * Fixes for related_part functionality * Fix removed stuff from merge99676ee* make more consistent * Show statistics for docstrings * add more docstrings * move specific register statements to make them clearer to understant * More docstrings for common * and more docstrings * and more * simpler call * docstrings for notifications * docstrings for common/tests * Add docs for common/models * Revert "move specific register statements to make them clearer to understant" This reverts commitca96654622. * use typing here * Revert "Make API code cleaner" This reverts commit24fb68bd3e. * docstring updates for the 'users' app * Add generic Meta info to simple Meta classes * remove unneeded unique_together statements * More simple metas * Remove unnecessary format specifier * Remove extra json format specifiers * Add docstrings for the 'plugin' app * Docstrings for the 'label' app * Add missing docstrings for the 'report' app * Fix build test regression * Fix top-level files * docstrings for InvenTree/InvenTree * reduce unneeded code * add docstrings * and more docstrings * more docstrings * more docstrings for stock * more docstrings * docstrings for order/views * Docstrings for various files in the 'order' app * Docstrings for order/test_api.py * Docstrings for order/serializers.py * Docstrings for order/admin.py * More docstrings for the order app * Add docstrings for the 'company' app * Add unit tests for rebuilding the reference fields * Prune out some more dead code * remove more dead code Co-authored-by: Oliver Walters <oliver.henry.walters@gmail.com>
This commit is contained in:
		| @@ -1,5 +1,4 @@ | ||||
| """ | ||||
| The Company module is responsible for managing Company interactions. | ||||
| """The Company module is responsible for managing Company interactions. | ||||
|  | ||||
| A company can be either (or both): | ||||
|  | ||||
|   | ||||
| @@ -1,3 +1,5 @@ | ||||
| """Admin class for the 'company' app""" | ||||
|  | ||||
| from django.contrib import admin | ||||
|  | ||||
| import import_export.widgets as widgets | ||||
| @@ -13,9 +15,10 @@ from .models import (Company, ManufacturerPart, ManufacturerPartAttachment, | ||||
|  | ||||
|  | ||||
| class CompanyResource(ModelResource): | ||||
|     """ Class for managing Company data import/export """ | ||||
|     """Class for managing Company data import/export.""" | ||||
|  | ||||
|     class Meta: | ||||
|         """Metaclass defines extra options""" | ||||
|         model = Company | ||||
|         skip_unchanged = True | ||||
|         report_skipped = False | ||||
| @@ -23,6 +26,7 @@ class CompanyResource(ModelResource): | ||||
|  | ||||
|  | ||||
| class CompanyAdmin(ImportExportModelAdmin): | ||||
|     """Admin class for the Company model""" | ||||
|  | ||||
|     resource_class = CompanyResource | ||||
|  | ||||
| @@ -35,9 +39,7 @@ class CompanyAdmin(ImportExportModelAdmin): | ||||
|  | ||||
|  | ||||
| class SupplierPartResource(ModelResource): | ||||
|     """ | ||||
|     Class for managing SupplierPart data import/export | ||||
|     """ | ||||
|     """Class for managing SupplierPart data import/export.""" | ||||
|  | ||||
|     part = Field(attribute='part', widget=widgets.ForeignKeyWidget(Part)) | ||||
|  | ||||
| @@ -48,6 +50,7 @@ class SupplierPartResource(ModelResource): | ||||
|     supplier_name = Field(attribute='supplier__name', readonly=True) | ||||
|  | ||||
|     class Meta: | ||||
|         """Metaclass defines extra admin options""" | ||||
|         model = SupplierPart | ||||
|         skip_unchanged = True | ||||
|         report_skipped = True | ||||
| @@ -55,6 +58,7 @@ class SupplierPartResource(ModelResource): | ||||
|  | ||||
|  | ||||
| class SupplierPartAdmin(ImportExportModelAdmin): | ||||
|     """Admin class for the SupplierPart model""" | ||||
|  | ||||
|     resource_class = SupplierPartResource | ||||
|  | ||||
| @@ -71,9 +75,7 @@ class SupplierPartAdmin(ImportExportModelAdmin): | ||||
|  | ||||
|  | ||||
| class ManufacturerPartResource(ModelResource): | ||||
|     """ | ||||
|     Class for managing ManufacturerPart data import/export | ||||
|     """ | ||||
|     """Class for managing ManufacturerPart data import/export.""" | ||||
|  | ||||
|     part = Field(attribute='part', widget=widgets.ForeignKeyWidget(Part)) | ||||
|  | ||||
| @@ -84,6 +86,7 @@ class ManufacturerPartResource(ModelResource): | ||||
|     manufacturer_name = Field(attribute='manufacturer__name', readonly=True) | ||||
|  | ||||
|     class Meta: | ||||
|         """Metaclass defines extra admin options""" | ||||
|         model = ManufacturerPart | ||||
|         skip_unchanged = True | ||||
|         report_skipped = True | ||||
| @@ -91,9 +94,7 @@ class ManufacturerPartResource(ModelResource): | ||||
|  | ||||
|  | ||||
| class ManufacturerPartAdmin(ImportExportModelAdmin): | ||||
|     """ | ||||
|     Admin class for ManufacturerPart model | ||||
|     """ | ||||
|     """Admin class for ManufacturerPart model.""" | ||||
|  | ||||
|     resource_class = ManufacturerPartResource | ||||
|  | ||||
| @@ -109,9 +110,7 @@ class ManufacturerPartAdmin(ImportExportModelAdmin): | ||||
|  | ||||
|  | ||||
| class ManufacturerPartAttachmentAdmin(ImportExportModelAdmin): | ||||
|     """ | ||||
|     Admin class for ManufacturerPartAttachment model | ||||
|     """ | ||||
|     """Admin class for ManufacturerPartAttachment model.""" | ||||
|  | ||||
|     list_display = ('manufacturer_part', 'attachment', 'comment') | ||||
|  | ||||
| @@ -119,11 +118,10 @@ class ManufacturerPartAttachmentAdmin(ImportExportModelAdmin): | ||||
|  | ||||
|  | ||||
| class ManufacturerPartParameterResource(ModelResource): | ||||
|     """ | ||||
|     Class for managing ManufacturerPartParameter data import/export | ||||
|     """ | ||||
|     """Class for managing ManufacturerPartParameter data import/export.""" | ||||
|  | ||||
|     class Meta: | ||||
|         """Metaclass defines extra admin options""" | ||||
|         model = ManufacturerPartParameter | ||||
|         skip_unchanged = True | ||||
|         report_skipped = True | ||||
| @@ -131,9 +129,7 @@ class ManufacturerPartParameterResource(ModelResource): | ||||
|  | ||||
|  | ||||
| class ManufacturerPartParameterAdmin(ImportExportModelAdmin): | ||||
|     """ | ||||
|     Admin class for ManufacturerPartParameter model | ||||
|     """ | ||||
|     """Admin class for ManufacturerPartParameter model.""" | ||||
|  | ||||
|     resource_class = ManufacturerPartParameterResource | ||||
|  | ||||
| @@ -149,7 +145,7 @@ class ManufacturerPartParameterAdmin(ImportExportModelAdmin): | ||||
|  | ||||
|  | ||||
| class SupplierPriceBreakResource(ModelResource): | ||||
|     """ Class for managing SupplierPriceBreak data import/export """ | ||||
|     """Class for managing SupplierPriceBreak data import/export.""" | ||||
|  | ||||
|     part = Field(attribute='part', widget=widgets.ForeignKeyWidget(SupplierPart)) | ||||
|  | ||||
| @@ -164,6 +160,7 @@ class SupplierPriceBreakResource(ModelResource): | ||||
|     MPN = Field(attribute='part__MPN', readonly=True) | ||||
|  | ||||
|     class Meta: | ||||
|         """Metaclass defines extra admin options""" | ||||
|         model = SupplierPriceBreak | ||||
|         skip_unchanged = True | ||||
|         report_skipped = False | ||||
| @@ -171,6 +168,7 @@ class SupplierPriceBreakResource(ModelResource): | ||||
|  | ||||
|  | ||||
| class SupplierPriceBreakAdmin(ImportExportModelAdmin): | ||||
|     """Admin class for the SupplierPriceBreak model""" | ||||
|  | ||||
|     resource_class = SupplierPriceBreakResource | ||||
|  | ||||
|   | ||||
| @@ -1,6 +1,4 @@ | ||||
| """ | ||||
| Provides a JSON API for the Company app | ||||
| """ | ||||
| """Provides a JSON API for the Company app.""" | ||||
|  | ||||
| from django.db.models import Q | ||||
| from django.urls import include, re_path | ||||
| @@ -23,7 +21,7 @@ from .serializers import (CompanySerializer, | ||||
|  | ||||
|  | ||||
| class CompanyList(generics.ListCreateAPIView): | ||||
|     """ API endpoint for accessing a list of Company objects | ||||
|     """API endpoint for accessing a list of Company objects. | ||||
|  | ||||
|     Provides two methods: | ||||
|  | ||||
| @@ -35,7 +33,7 @@ class CompanyList(generics.ListCreateAPIView): | ||||
|     queryset = Company.objects.all() | ||||
|  | ||||
|     def get_queryset(self): | ||||
|  | ||||
|         """Return annotated queryset for the company list endpoint""" | ||||
|         queryset = super().get_queryset() | ||||
|         queryset = CompanySerializer.annotate_queryset(queryset) | ||||
|  | ||||
| @@ -70,13 +68,13 @@ class CompanyList(generics.ListCreateAPIView): | ||||
|  | ||||
|  | ||||
| class CompanyDetail(generics.RetrieveUpdateDestroyAPIView): | ||||
|     """ API endpoint for detail of a single Company object """ | ||||
|     """API endpoint for detail of a single Company object.""" | ||||
|  | ||||
|     queryset = Company.objects.all() | ||||
|     serializer_class = CompanySerializer | ||||
|  | ||||
|     def get_queryset(self): | ||||
|  | ||||
|         """Return annotated queryset for the company detail endpoint""" | ||||
|         queryset = super().get_queryset() | ||||
|         queryset = CompanySerializer.annotate_queryset(queryset) | ||||
|  | ||||
| @@ -84,11 +82,11 @@ class CompanyDetail(generics.RetrieveUpdateDestroyAPIView): | ||||
|  | ||||
|  | ||||
| class ManufacturerPartFilter(rest_filters.FilterSet): | ||||
|     """ | ||||
|     Custom API filters for the ManufacturerPart list endpoint. | ||||
|     """ | ||||
|     """Custom API filters for the ManufacturerPart list endpoint.""" | ||||
|  | ||||
|     class Meta: | ||||
|         """Metaclass options.""" | ||||
|  | ||||
|         model = ManufacturerPart | ||||
|         fields = [ | ||||
|             'manufacturer', | ||||
| @@ -101,7 +99,7 @@ class ManufacturerPartFilter(rest_filters.FilterSet): | ||||
|  | ||||
|  | ||||
| class ManufacturerPartList(generics.ListCreateAPIView): | ||||
|     """ API endpoint for list view of ManufacturerPart object | ||||
|     """API endpoint for list view of ManufacturerPart object. | ||||
|  | ||||
|     - GET: Return list of ManufacturerPart objects | ||||
|     - POST: Create a new ManufacturerPart object | ||||
| @@ -117,7 +115,7 @@ class ManufacturerPartList(generics.ListCreateAPIView): | ||||
|     filterset_class = ManufacturerPartFilter | ||||
|  | ||||
|     def get_serializer(self, *args, **kwargs): | ||||
|  | ||||
|         """Return serializer instance for this endpoint""" | ||||
|         # Do we wish to include extra detail? | ||||
|         try: | ||||
|             params = self.request.query_params | ||||
| @@ -149,7 +147,7 @@ class ManufacturerPartList(generics.ListCreateAPIView): | ||||
|  | ||||
|  | ||||
| class ManufacturerPartDetail(generics.RetrieveUpdateDestroyAPIView): | ||||
|     """ API endpoint for detail view of ManufacturerPart object | ||||
|     """API endpoint for detail view of ManufacturerPart object. | ||||
|  | ||||
|     - GET: Retrieve detail view | ||||
|     - PATCH: Update object | ||||
| @@ -161,9 +159,7 @@ class ManufacturerPartDetail(generics.RetrieveUpdateDestroyAPIView): | ||||
|  | ||||
|  | ||||
| class ManufacturerPartAttachmentList(AttachmentMixin, generics.ListCreateAPIView): | ||||
|     """ | ||||
|     API endpoint for listing (and creating) a ManufacturerPartAttachment (file upload). | ||||
|     """ | ||||
|     """API endpoint for listing (and creating) a ManufacturerPartAttachment (file upload).""" | ||||
|  | ||||
|     queryset = ManufacturerPartAttachment.objects.all() | ||||
|     serializer_class = ManufacturerPartAttachmentSerializer | ||||
| @@ -178,24 +174,20 @@ class ManufacturerPartAttachmentList(AttachmentMixin, generics.ListCreateAPIView | ||||
|  | ||||
|  | ||||
| class ManufacturerPartAttachmentDetail(AttachmentMixin, generics.RetrieveUpdateDestroyAPIView): | ||||
|     """ | ||||
|     Detail endpooint for ManufacturerPartAttachment model | ||||
|     """ | ||||
|     """Detail endpooint for ManufacturerPartAttachment model.""" | ||||
|  | ||||
|     queryset = ManufacturerPartAttachment.objects.all() | ||||
|     serializer_class = ManufacturerPartAttachmentSerializer | ||||
|  | ||||
|  | ||||
| class ManufacturerPartParameterList(generics.ListCreateAPIView): | ||||
|     """ | ||||
|     API endpoint for list view of ManufacturerPartParamater model. | ||||
|     """ | ||||
|     """API endpoint for list view of ManufacturerPartParamater model.""" | ||||
|  | ||||
|     queryset = ManufacturerPartParameter.objects.all() | ||||
|     serializer_class = ManufacturerPartParameterSerializer | ||||
|  | ||||
|     def get_serializer(self, *args, **kwargs): | ||||
|  | ||||
|         """Return serializer instance for this endpoint""" | ||||
|         # Do we wish to include any extra detail? | ||||
|         try: | ||||
|             params = self.request.query_params | ||||
| @@ -215,10 +207,7 @@ class ManufacturerPartParameterList(generics.ListCreateAPIView): | ||||
|         return self.serializer_class(*args, **kwargs) | ||||
|  | ||||
|     def filter_queryset(self, queryset): | ||||
|         """ | ||||
|         Custom filtering for the queryset | ||||
|         """ | ||||
|  | ||||
|         """Custom filtering for the queryset.""" | ||||
|         queryset = super().filter_queryset(queryset) | ||||
|  | ||||
|         params = self.request.query_params | ||||
| @@ -258,16 +247,14 @@ class ManufacturerPartParameterList(generics.ListCreateAPIView): | ||||
|  | ||||
|  | ||||
| class ManufacturerPartParameterDetail(generics.RetrieveUpdateDestroyAPIView): | ||||
|     """ | ||||
|     API endpoint for detail view of ManufacturerPartParameter model | ||||
|     """ | ||||
|     """API endpoint for detail view of ManufacturerPartParameter model.""" | ||||
|  | ||||
|     queryset = ManufacturerPartParameter.objects.all() | ||||
|     serializer_class = ManufacturerPartParameterSerializer | ||||
|  | ||||
|  | ||||
| class SupplierPartList(generics.ListCreateAPIView): | ||||
|     """ API endpoint for list view of SupplierPart object | ||||
|     """API endpoint for list view of SupplierPart object. | ||||
|  | ||||
|     - GET: Return list of SupplierPart objects | ||||
|     - POST: Create a new SupplierPart object | ||||
| @@ -275,17 +262,8 @@ class SupplierPartList(generics.ListCreateAPIView): | ||||
|  | ||||
|     queryset = SupplierPart.objects.all() | ||||
|  | ||||
|     def get_queryset(self): | ||||
|  | ||||
|         queryset = super().get_queryset() | ||||
|  | ||||
|         return queryset | ||||
|  | ||||
|     def filter_queryset(self, queryset): | ||||
|         """ | ||||
|         Custom filtering for the queryset. | ||||
|         """ | ||||
|  | ||||
|         """Custom filtering for the queryset.""" | ||||
|         queryset = super().filter_queryset(queryset) | ||||
|  | ||||
|         params = self.request.query_params | ||||
| @@ -330,6 +308,7 @@ class SupplierPartList(generics.ListCreateAPIView): | ||||
|         return queryset | ||||
|  | ||||
|     def get_serializer(self, *args, **kwargs): | ||||
|         """Return serializer instance for this endpoint""" | ||||
|  | ||||
|         # Do we wish to include extra detail? | ||||
|         try: | ||||
| @@ -369,7 +348,7 @@ class SupplierPartList(generics.ListCreateAPIView): | ||||
|  | ||||
|  | ||||
| class SupplierPartDetail(generics.RetrieveUpdateDestroyAPIView): | ||||
|     """ API endpoint for detail view of SupplierPart object | ||||
|     """API endpoint for detail view of SupplierPart object. | ||||
|  | ||||
|     - GET: Retrieve detail view | ||||
|     - PATCH: Update object | ||||
| @@ -384,7 +363,7 @@ class SupplierPartDetail(generics.RetrieveUpdateDestroyAPIView): | ||||
|  | ||||
|  | ||||
| class SupplierPriceBreakList(generics.ListCreateAPIView): | ||||
|     """ API endpoint for list view of SupplierPriceBreak object | ||||
|     """API endpoint for list view of SupplierPriceBreak object. | ||||
|  | ||||
|     - GET: Retrieve list of SupplierPriceBreak objects | ||||
|     - POST: Create a new SupplierPriceBreak object | ||||
| @@ -403,9 +382,7 @@ class SupplierPriceBreakList(generics.ListCreateAPIView): | ||||
|  | ||||
|  | ||||
| class SupplierPriceBreakDetail(generics.RetrieveUpdateDestroyAPIView): | ||||
|     """ | ||||
|     Detail endpoint for SupplierPriceBreak object | ||||
|     """ | ||||
|     """Detail endpoint for SupplierPriceBreak object.""" | ||||
|  | ||||
|     queryset = SupplierPriceBreak.objects.all() | ||||
|     serializer_class = SupplierPriceBreakSerializer | ||||
|   | ||||
| @@ -1,12 +1,13 @@ | ||||
| """Config for the 'company' app""" | ||||
|  | ||||
| from django.apps import AppConfig | ||||
|  | ||||
|  | ||||
| class CompanyConfig(AppConfig): | ||||
|     """Config class for the 'company' app""" | ||||
|  | ||||
|     name = 'company' | ||||
|  | ||||
|     def ready(self): | ||||
|         """ | ||||
|         This function is called whenever the Company app is loaded. | ||||
|         """ | ||||
|  | ||||
|         """This function is called whenever the Company app is loaded.""" | ||||
|         pass | ||||
|   | ||||
| @@ -1,6 +1,4 @@ | ||||
| """ | ||||
| Django Forms for interacting with Company app | ||||
| """ | ||||
| """Django Forms for interacting with Company app.""" | ||||
|  | ||||
| import django.forms | ||||
| from django.utils.translation import gettext_lazy as _ | ||||
| @@ -12,9 +10,7 @@ from .models import Company, SupplierPriceBreak | ||||
|  | ||||
|  | ||||
| class CompanyImageDownloadForm(HelperForm): | ||||
|     """ | ||||
|     Form for downloading an image from a URL | ||||
|     """ | ||||
|     """Form for downloading an image from a URL.""" | ||||
|  | ||||
|     url = django.forms.URLField( | ||||
|         label=_('URL'), | ||||
| @@ -23,6 +19,8 @@ class CompanyImageDownloadForm(HelperForm): | ||||
|     ) | ||||
|  | ||||
|     class Meta: | ||||
|         """Metaclass options.""" | ||||
|  | ||||
|         model = Company | ||||
|         fields = [ | ||||
|             'url', | ||||
| @@ -30,7 +28,7 @@ class CompanyImageDownloadForm(HelperForm): | ||||
|  | ||||
|  | ||||
| class EditPriceBreakForm(HelperForm): | ||||
|     """ Form for creating / editing a supplier price break """ | ||||
|     """Form for creating / editing a supplier price break.""" | ||||
|  | ||||
|     quantity = RoundingDecimalFormField( | ||||
|         max_digits=10, | ||||
| @@ -40,6 +38,8 @@ class EditPriceBreakForm(HelperForm): | ||||
|     ) | ||||
|  | ||||
|     class Meta: | ||||
|         """Metaclass options.""" | ||||
|  | ||||
|         model = SupplierPriceBreak | ||||
|         fields = [ | ||||
|             'part', | ||||
|   | ||||
| @@ -1,6 +1,4 @@ | ||||
| """ | ||||
| Company database model definitions | ||||
| """ | ||||
| """Company database model definitions.""" | ||||
|  | ||||
| import os | ||||
|  | ||||
| @@ -27,7 +25,7 @@ from InvenTree.status_codes import PurchaseOrderStatus | ||||
|  | ||||
|  | ||||
| def rename_company_image(instance, filename): | ||||
|     """ Function to rename a company image after upload | ||||
|     """Function to rename a company image after upload. | ||||
|  | ||||
|     Args: | ||||
|         instance: Company object | ||||
| @@ -36,7 +34,6 @@ def rename_company_image(instance, filename): | ||||
|     Returns: | ||||
|         New image filename | ||||
|     """ | ||||
|  | ||||
|     base = 'company_images' | ||||
|  | ||||
|     if filename.count('.') > 0: | ||||
| @@ -53,7 +50,8 @@ def rename_company_image(instance, filename): | ||||
|  | ||||
|  | ||||
| class Company(models.Model): | ||||
|     """ A Company object represents an external company. | ||||
|     """A Company object represents an external company. | ||||
|  | ||||
|     It may be a supplier or a customer or a manufacturer (or a combination) | ||||
|  | ||||
|     - A supplier is a company from which parts can be purchased | ||||
| @@ -79,9 +77,11 @@ class Company(models.Model): | ||||
|  | ||||
|     @staticmethod | ||||
|     def get_api_url(): | ||||
|         """Return the API URL associated with the Company model""" | ||||
|         return reverse('api-company-list') | ||||
|  | ||||
|     class Meta: | ||||
|         """Metaclass defines extra model options""" | ||||
|         ordering = ['name', ] | ||||
|         constraints = [ | ||||
|             UniqueConstraint(fields=['name', 'email'], name='unique_name_email_pair') | ||||
| @@ -150,13 +150,11 @@ class Company(models.Model): | ||||
|  | ||||
|     @property | ||||
|     def currency_code(self): | ||||
|         """ | ||||
|         Return the currency code associated with this company. | ||||
|         """Return the currency code associated with this company. | ||||
|  | ||||
|         - If the currency code is invalid, use the default currency | ||||
|         - If the currency code is not specified, use the default currency | ||||
|         """ | ||||
|  | ||||
|         code = self.currency | ||||
|  | ||||
|         if code not in CURRENCIES: | ||||
| @@ -165,103 +163,41 @@ class Company(models.Model): | ||||
|         return code | ||||
|  | ||||
|     def __str__(self): | ||||
|         """ Get string representation of a Company """ | ||||
|         """Get string representation of a Company.""" | ||||
|         return "{n} - {d}".format(n=self.name, d=self.description) | ||||
|  | ||||
|     def get_absolute_url(self): | ||||
|         """ Get the web URL for the detail view for this Company """ | ||||
|         """Get the web URL for the detail view for this Company.""" | ||||
|         return reverse('company-detail', kwargs={'pk': self.id}) | ||||
|  | ||||
|     def get_image_url(self): | ||||
|         """ Return the URL of the image for this company """ | ||||
|  | ||||
|         """Return the URL of the image for this company.""" | ||||
|         if self.image: | ||||
|             return getMediaUrl(self.image.url) | ||||
|         else: | ||||
|             return getBlankImage() | ||||
|  | ||||
|     def get_thumbnail_url(self): | ||||
|         """ Return the URL for the thumbnail image for this Company """ | ||||
|  | ||||
|         """Return the URL for the thumbnail image for this Company.""" | ||||
|         if self.image: | ||||
|             return getMediaUrl(self.image.thumbnail.url) | ||||
|         else: | ||||
|             return getBlankThumbnail() | ||||
|  | ||||
|     @property | ||||
|     def manufactured_part_count(self): | ||||
|         """ The number of parts manufactured by this company """ | ||||
|         return self.manufactured_parts.count() | ||||
|  | ||||
|     @property | ||||
|     def has_manufactured_parts(self): | ||||
|         return self.manufactured_part_count > 0 | ||||
|  | ||||
|     @property | ||||
|     def supplied_part_count(self): | ||||
|         """ The number of parts supplied by this company """ | ||||
|         return self.supplied_parts.count() | ||||
|  | ||||
|     @property | ||||
|     def has_supplied_parts(self): | ||||
|         """ Return True if this company supplies any parts """ | ||||
|         return self.supplied_part_count > 0 | ||||
|  | ||||
|     @property | ||||
|     def parts(self): | ||||
|         """ Return SupplierPart objects which are supplied or manufactured by this company """ | ||||
|         """Return SupplierPart objects which are supplied or manufactured by this company.""" | ||||
|         return SupplierPart.objects.filter(Q(supplier=self.id) | Q(manufacturer_part__manufacturer=self.id)) | ||||
|  | ||||
|     @property | ||||
|     def part_count(self): | ||||
|         """ The number of parts manufactured (or supplied) by this Company """ | ||||
|         return self.parts.count() | ||||
|  | ||||
|     @property | ||||
|     def has_parts(self): | ||||
|         return self.part_count > 0 | ||||
|  | ||||
|     @property | ||||
|     def stock_items(self): | ||||
|         """ Return a list of all stock items supplied or manufactured by this company """ | ||||
|         """Return a list of all stock items supplied or manufactured by this company.""" | ||||
|         stock = apps.get_model('stock', 'StockItem') | ||||
|         return stock.objects.filter(Q(supplier_part__supplier=self.id) | Q(supplier_part__manufacturer_part__manufacturer=self.id)).all() | ||||
|  | ||||
|     @property | ||||
|     def stock_count(self): | ||||
|         """ Return the number of stock items supplied or manufactured by this company """ | ||||
|         return self.stock_items.count() | ||||
|  | ||||
|     def outstanding_purchase_orders(self): | ||||
|         """ Return purchase orders which are 'outstanding' """ | ||||
|         return self.purchase_orders.filter(status__in=PurchaseOrderStatus.OPEN) | ||||
|  | ||||
|     def pending_purchase_orders(self): | ||||
|         """ Return purchase orders which are PENDING (not yet issued) """ | ||||
|         return self.purchase_orders.filter(status=PurchaseOrderStatus.PENDING) | ||||
|  | ||||
|     def closed_purchase_orders(self): | ||||
|         """ Return purchase orders which are not 'outstanding' | ||||
|  | ||||
|         - Complete | ||||
|         - Failed / lost | ||||
|         - Returned | ||||
|         """ | ||||
|  | ||||
|         return self.purchase_orders.exclude(status__in=PurchaseOrderStatus.OPEN) | ||||
|  | ||||
|     def complete_purchase_orders(self): | ||||
|         return self.purchase_orders.filter(status=PurchaseOrderStatus.COMPLETE) | ||||
|  | ||||
|     def failed_purchase_orders(self): | ||||
|         """ Return any purchase orders which were not successful """ | ||||
|  | ||||
|         return self.purchase_orders.filter(status__in=PurchaseOrderStatus.FAILED) | ||||
|  | ||||
|  | ||||
| class Contact(models.Model): | ||||
|     """ A Contact represents a person who works at a particular company. | ||||
|     A Company may have zero or more associated Contact objects. | ||||
|     """A Contact represents a person who works at a particular company. A Company may have zero or more associated Contact objects. | ||||
|  | ||||
|     Attributes: | ||||
|         company: Company link for this contact | ||||
| @@ -284,10 +220,7 @@ class Contact(models.Model): | ||||
|  | ||||
|  | ||||
| class ManufacturerPart(models.Model): | ||||
|     """ 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 | ||||
|     """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. | ||||
|  | ||||
|     Attributes: | ||||
|         part: Link to the master Part | ||||
| @@ -299,9 +232,11 @@ class ManufacturerPart(models.Model): | ||||
|  | ||||
|     @staticmethod | ||||
|     def get_api_url(): | ||||
|         """Return the API URL associated with the ManufacturerPart instance""" | ||||
|         return reverse('api-manufacturer-part-list') | ||||
|  | ||||
|     class Meta: | ||||
|         """Metaclass defines extra model options""" | ||||
|         unique_together = ('part', 'manufacturer', 'MPN') | ||||
|  | ||||
|     part = models.ForeignKey('part.Part', on_delete=models.CASCADE, | ||||
| @@ -346,10 +281,7 @@ class ManufacturerPart(models.Model): | ||||
|  | ||||
|     @classmethod | ||||
|     def create(cls, part, manufacturer, mpn, description, link=None): | ||||
|         """ Check if ManufacturerPart instance does not already exist | ||||
|             then create it | ||||
|         """ | ||||
|  | ||||
|         """Check if ManufacturerPart instance does not already exist then create it.""" | ||||
|         manufacturer_part = None | ||||
|  | ||||
|         try: | ||||
| @@ -364,6 +296,7 @@ class ManufacturerPart(models.Model): | ||||
|         return manufacturer_part | ||||
|  | ||||
|     def __str__(self): | ||||
|         """Format a string representation of a ManufacturerPart""" | ||||
|         s = '' | ||||
|  | ||||
|         if self.manufacturer: | ||||
| @@ -376,15 +309,15 @@ class ManufacturerPart(models.Model): | ||||
|  | ||||
|  | ||||
| class ManufacturerPartAttachment(InvenTreeAttachment): | ||||
|     """ | ||||
|     Model for storing file attachments against a ManufacturerPart object | ||||
|     """ | ||||
|     """Model for storing file attachments against a ManufacturerPart object.""" | ||||
|  | ||||
|     @staticmethod | ||||
|     def get_api_url(): | ||||
|         """Return the API URL associated with the ManufacturerPartAttachment model""" | ||||
|         return reverse('api-manufacturer-part-attachment-list') | ||||
|  | ||||
|     def getSubdir(self): | ||||
|         """Return the subdirectory where attachment files for the ManufacturerPart model are located""" | ||||
|         return os.path.join("manufacturer_part_files", str(self.manufacturer_part.id)) | ||||
|  | ||||
|     manufacturer_part = models.ForeignKey(ManufacturerPart, on_delete=models.CASCADE, | ||||
| @@ -392,8 +325,7 @@ class ManufacturerPartAttachment(InvenTreeAttachment): | ||||
|  | ||||
|  | ||||
| class ManufacturerPartParameter(models.Model): | ||||
|     """ | ||||
|     A ManufacturerPartParameter represents a key:value parameter for a MnaufacturerPart. | ||||
|     """A ManufacturerPartParameter represents a key:value parameter for a MnaufacturerPart. | ||||
|  | ||||
|     This is used to represent parmeters / properties for a particular manufacturer part. | ||||
|  | ||||
| @@ -402,9 +334,11 @@ class ManufacturerPartParameter(models.Model): | ||||
|  | ||||
|     @staticmethod | ||||
|     def get_api_url(): | ||||
|         """Return the API URL associated with the ManufacturerPartParameter model""" | ||||
|         return reverse('api-manufacturer-part-parameter-list') | ||||
|  | ||||
|     class Meta: | ||||
|         """Metaclass defines extra model options""" | ||||
|         unique_together = ('manufacturer_part', 'name') | ||||
|  | ||||
|     manufacturer_part = models.ForeignKey( | ||||
| @@ -437,13 +371,14 @@ class ManufacturerPartParameter(models.Model): | ||||
|  | ||||
|  | ||||
| class SupplierPartManager(models.Manager): | ||||
|     """ Define custom SupplierPart objects manager | ||||
|     """Define custom SupplierPart objects manager. | ||||
|  | ||||
|         The main purpose of this manager is to improve database hit as the | ||||
|         SupplierPart model involves A LOT of foreign keys lookups | ||||
|     The main purpose of this manager is to improve database hit as the | ||||
|     SupplierPart model involves A LOT of foreign keys lookups | ||||
|     """ | ||||
|  | ||||
|     def get_queryset(self): | ||||
|         """Prefetch related fields when querying against the SupplierPart model""" | ||||
|         # Always prefetch related models | ||||
|         return super().get_queryset().prefetch_related( | ||||
|             'part', | ||||
| @@ -453,10 +388,7 @@ class SupplierPartManager(models.Manager): | ||||
|  | ||||
|  | ||||
| class SupplierPart(models.Model): | ||||
|     """ Represents a unique part as provided by a Supplier | ||||
|     Each SupplierPart is identified by a SKU (Supplier Part Number) | ||||
|     Each SupplierPart is also linked to a Part or ManufacturerPart object. | ||||
|     A Part may be available from multiple suppliers | ||||
|     """Represents a unique part as provided by a Supplier Each SupplierPart is identified by a SKU (Supplier Part Number) Each SupplierPart is also linked to a Part or ManufacturerPart object. A Part may be available from multiple suppliers. | ||||
|  | ||||
|     Attributes: | ||||
|         part: Link to the master Part (Obsolete) | ||||
| @@ -476,13 +408,15 @@ class SupplierPart(models.Model): | ||||
|  | ||||
|     @staticmethod | ||||
|     def get_api_url(): | ||||
|         """Return the API URL associated with the SupplierPart model""" | ||||
|         return reverse('api-supplier-part-list') | ||||
|  | ||||
|     def get_absolute_url(self): | ||||
|         """Return the web URL of the detail view for this SupplierPart""" | ||||
|         return reverse('supplier-part-detail', kwargs={'pk': self.id}) | ||||
|  | ||||
|     def api_instance_filters(self): | ||||
|  | ||||
|         """Return custom API filters for this particular instance""" | ||||
|         return { | ||||
|             'manufacturer_part': { | ||||
|                 'part': self.part.pk | ||||
| @@ -490,13 +424,17 @@ class SupplierPart(models.Model): | ||||
|         } | ||||
|  | ||||
|     class Meta: | ||||
|         """Metaclass defines extra model options""" | ||||
|         unique_together = ('part', 'supplier', 'SKU') | ||||
|  | ||||
|         # This model was moved from the 'Part' app | ||||
|         db_table = 'part_supplierpart' | ||||
|  | ||||
|     def clean(self): | ||||
|         """Custom clean action for the SupplierPart model: | ||||
|  | ||||
|         - Ensure that manufacturer_part.part and part are the same! | ||||
|         """ | ||||
|         super().clean() | ||||
|  | ||||
|         # Ensure that the linked manufacturer_part points to the same part! | ||||
| @@ -508,8 +446,7 @@ class SupplierPart(models.Model): | ||||
|                 }) | ||||
|  | ||||
|     def save(self, *args, **kwargs): | ||||
|         """ Overriding save method to connect an existing ManufacturerPart """ | ||||
|  | ||||
|         """Overriding save method to connect an existing ManufacturerPart.""" | ||||
|         manufacturer_part = None | ||||
|  | ||||
|         if all(key in kwargs for key in ('manufacturer', 'MPN')): | ||||
| @@ -593,10 +530,10 @@ class SupplierPart(models.Model): | ||||
|  | ||||
|     @property | ||||
|     def manufacturer_string(self): | ||||
|         """ Format a MPN string for this SupplierPart. | ||||
|         """Format a MPN string for this SupplierPart. | ||||
|  | ||||
|         Concatenates manufacture name and part number. | ||||
|         """ | ||||
|  | ||||
|         items = [] | ||||
|  | ||||
|         if self.manufacturer_part: | ||||
| @@ -609,26 +546,26 @@ class SupplierPart(models.Model): | ||||
|  | ||||
|     @property | ||||
|     def has_price_breaks(self): | ||||
|         """Return True if this SupplierPart has associated price breaks""" | ||||
|         return self.price_breaks.count() > 0 | ||||
|  | ||||
|     @property | ||||
|     def price_breaks(self): | ||||
|         """ Return the associated price breaks in the correct order """ | ||||
|         """Return the associated price breaks in the correct order.""" | ||||
|         return self.pricebreaks.order_by('quantity').all() | ||||
|  | ||||
|     @property | ||||
|     def unit_pricing(self): | ||||
|         """Return the single-quantity pricing for this SupplierPart""" | ||||
|         return self.get_price(1) | ||||
|  | ||||
|     def add_price_break(self, quantity, price): | ||||
|         """ | ||||
|         Create a new price break for this part | ||||
|     def add_price_break(self, quantity, price) -> None: | ||||
|         """Create a new price break for this part. | ||||
|  | ||||
|         args: | ||||
|             quantity - Numerical quantity | ||||
|             price - Must be a Money object | ||||
|         Args: | ||||
|             quantity: Numerical quantity | ||||
|             price: Must be a Money object | ||||
|         """ | ||||
|  | ||||
|         # Check if a price break at that quantity already exists... | ||||
|         if self.price_breaks.filter(quantity=quantity, part=self.pk).exists(): | ||||
|             return | ||||
| @@ -642,18 +579,14 @@ class SupplierPart(models.Model): | ||||
|     get_price = common.models.get_price | ||||
|  | ||||
|     def open_orders(self): | ||||
|         """ Return a database query for PurchaseOrder line items for this SupplierPart, | ||||
|         limited to purchase orders that are open / outstanding. | ||||
|         """ | ||||
|  | ||||
|         """Return a database query for PurchaseOrder line items for this SupplierPart, limited to purchase orders that are open / outstanding.""" | ||||
|         return self.purchase_order_line_items.prefetch_related('order').filter(order__status__in=PurchaseOrderStatus.OPEN) | ||||
|  | ||||
|     def on_order(self): | ||||
|         """ Return the total quantity of items currently on order. | ||||
|         """Return the total quantity of items currently on order. | ||||
|  | ||||
|         Subtract partially received stock as appropriate | ||||
|         """ | ||||
|  | ||||
|         totals = self.open_orders().aggregate(Sum('quantity'), Sum('received')) | ||||
|  | ||||
|         # Quantity on order | ||||
| @@ -668,15 +601,16 @@ class SupplierPart(models.Model): | ||||
|             return max(q - r, 0) | ||||
|  | ||||
|     def purchase_orders(self): | ||||
|         """ Returns a list of purchase orders relating to this supplier part """ | ||||
|  | ||||
|         """Returns a list of purchase orders relating to this supplier part.""" | ||||
|         return [line.order for line in self.purchase_order_line_items.all().prefetch_related('order')] | ||||
|  | ||||
|     @property | ||||
|     def pretty_name(self): | ||||
|         """Format a 'pretty' name for this SupplierPart""" | ||||
|         return str(self) | ||||
|  | ||||
|     def __str__(self): | ||||
|         """Format a string representation of a SupplierPart""" | ||||
|         s = '' | ||||
|  | ||||
|         if self.part.IPN: | ||||
| @@ -692,7 +626,8 @@ class SupplierPart(models.Model): | ||||
|  | ||||
|  | ||||
| class SupplierPriceBreak(common.models.PriceBreak): | ||||
|     """ Represents a quantity price break for a SupplierPart. | ||||
|     """Represents a quantity price break for a SupplierPart. | ||||
|  | ||||
|     - Suppliers can offer discounts at larger quantities | ||||
|     - SupplierPart(s) may have zero-or-more associated SupplierPriceBreak(s) | ||||
|  | ||||
| @@ -706,6 +641,7 @@ class SupplierPriceBreak(common.models.PriceBreak): | ||||
|  | ||||
|     @staticmethod | ||||
|     def get_api_url(): | ||||
|         """Return the API URL associated with the SupplierPriceBreak model""" | ||||
|         return reverse('api-part-supplier-price-list') | ||||
|  | ||||
|     part = models.ForeignKey(SupplierPart, on_delete=models.CASCADE, related_name='pricebreaks', verbose_name=_('Part'),) | ||||
| @@ -713,10 +649,12 @@ class SupplierPriceBreak(common.models.PriceBreak): | ||||
|     updated = models.DateTimeField(auto_now=True, null=True, verbose_name=_('last updated')) | ||||
|  | ||||
|     class Meta: | ||||
|         """Metaclass defines extra model options""" | ||||
|         unique_together = ("part", "quantity") | ||||
|  | ||||
|         # This model was moved from the 'Part' app | ||||
|         db_table = 'part_supplierpricebreak' | ||||
|  | ||||
|     def __str__(self): | ||||
|         """Format a string representation of a SupplierPriceBreak instance""" | ||||
|         return f'{self.part.SKU} - {self.price} @ {self.quantity}' | ||||
|   | ||||
| @@ -1,6 +1,4 @@ | ||||
| """ | ||||
| JSON serializers for Company app | ||||
| """ | ||||
| """JSON serializers for Company app.""" | ||||
|  | ||||
| from django.utils.translation import gettext_lazy as _ | ||||
|  | ||||
| @@ -21,13 +19,15 @@ from .models import (Company, ManufacturerPart, ManufacturerPartAttachment, | ||||
|  | ||||
|  | ||||
| class CompanyBriefSerializer(InvenTreeModelSerializer): | ||||
|     """ Serializer for Company object (limited detail) """ | ||||
|     """Serializer for Company object (limited detail)""" | ||||
|  | ||||
|     url = serializers.CharField(source='get_absolute_url', read_only=True) | ||||
|  | ||||
|     image = serializers.CharField(source='get_thumbnail_url', read_only=True) | ||||
|  | ||||
|     class Meta: | ||||
|         """Metaclass options.""" | ||||
|  | ||||
|         model = Company | ||||
|         fields = [ | ||||
|             'pk', | ||||
| @@ -39,11 +39,11 @@ class CompanyBriefSerializer(InvenTreeModelSerializer): | ||||
|  | ||||
|  | ||||
| class CompanySerializer(InvenTreeModelSerializer): | ||||
|     """ Serializer for Company object (full detail) """ | ||||
|     """Serializer for Company object (full detail)""" | ||||
|  | ||||
|     @staticmethod | ||||
|     def annotate_queryset(queryset): | ||||
|  | ||||
|         """Annoate the supplied queryset with aggregated information""" | ||||
|         # Add count of parts manufactured | ||||
|         queryset = queryset.annotate( | ||||
|             parts_manufactured=SubqueryCount('manufactured_parts') | ||||
| @@ -71,6 +71,8 @@ class CompanySerializer(InvenTreeModelSerializer): | ||||
|     ) | ||||
|  | ||||
|     class Meta: | ||||
|         """Metaclass options.""" | ||||
|  | ||||
|         model = Company | ||||
|         fields = [ | ||||
|             'pk', | ||||
| @@ -96,9 +98,7 @@ class CompanySerializer(InvenTreeModelSerializer): | ||||
|  | ||||
|  | ||||
| class ManufacturerPartSerializer(InvenTreeModelSerializer): | ||||
|     """ | ||||
|     Serializer for ManufacturerPart object | ||||
|     """ | ||||
|     """Serializer for ManufacturerPart object.""" | ||||
|  | ||||
|     part_detail = PartBriefSerializer(source='part', many=False, read_only=True) | ||||
|  | ||||
| @@ -107,7 +107,7 @@ class ManufacturerPartSerializer(InvenTreeModelSerializer): | ||||
|     pretty_name = serializers.CharField(read_only=True) | ||||
|  | ||||
|     def __init__(self, *args, **kwargs): | ||||
|  | ||||
|         """Initialize this serializer with extra detail fields as required""" | ||||
|         part_detail = kwargs.pop('part_detail', True) | ||||
|         manufacturer_detail = kwargs.pop('manufacturer_detail', True) | ||||
|         prettify = kwargs.pop('pretty', False) | ||||
| @@ -126,6 +126,8 @@ class ManufacturerPartSerializer(InvenTreeModelSerializer): | ||||
|     manufacturer = serializers.PrimaryKeyRelatedField(queryset=Company.objects.filter(is_manufacturer=True)) | ||||
|  | ||||
|     class Meta: | ||||
|         """Metaclass options.""" | ||||
|  | ||||
|         model = ManufacturerPart | ||||
|         fields = [ | ||||
|             'pk', | ||||
| @@ -141,11 +143,11 @@ class ManufacturerPartSerializer(InvenTreeModelSerializer): | ||||
|  | ||||
|  | ||||
| class ManufacturerPartAttachmentSerializer(InvenTreeAttachmentSerializer): | ||||
|     """ | ||||
|     Serializer for the ManufacturerPartAttachment class | ||||
|     """ | ||||
|     """Serializer for the ManufacturerPartAttachment class.""" | ||||
|  | ||||
|     class Meta: | ||||
|         """Metaclass options.""" | ||||
|  | ||||
|         model = ManufacturerPartAttachment | ||||
|  | ||||
|         fields = [ | ||||
| @@ -164,14 +166,12 @@ class ManufacturerPartAttachmentSerializer(InvenTreeAttachmentSerializer): | ||||
|  | ||||
|  | ||||
| class ManufacturerPartParameterSerializer(InvenTreeModelSerializer): | ||||
|     """ | ||||
|     Serializer for the ManufacturerPartParameter model | ||||
|     """ | ||||
|     """Serializer for the ManufacturerPartParameter model.""" | ||||
|  | ||||
|     manufacturer_part_detail = ManufacturerPartSerializer(source='manufacturer_part', many=False, read_only=True) | ||||
|  | ||||
|     def __init__(self, *args, **kwargs): | ||||
|  | ||||
|         """Initialize this serializer with extra detail fields as required""" | ||||
|         man_detail = kwargs.pop('manufacturer_part_detail', False) | ||||
|  | ||||
|         super(ManufacturerPartParameterSerializer, self).__init__(*args, **kwargs) | ||||
| @@ -180,6 +180,8 @@ class ManufacturerPartParameterSerializer(InvenTreeModelSerializer): | ||||
|             self.fields.pop('manufacturer_part_detail') | ||||
|  | ||||
|     class Meta: | ||||
|         """Metaclass options.""" | ||||
|  | ||||
|         model = ManufacturerPartParameter | ||||
|  | ||||
|         fields = [ | ||||
| @@ -193,7 +195,7 @@ class ManufacturerPartParameterSerializer(InvenTreeModelSerializer): | ||||
|  | ||||
|  | ||||
| class SupplierPartSerializer(InvenTreeModelSerializer): | ||||
|     """ Serializer for SupplierPart object """ | ||||
|     """Serializer for SupplierPart object.""" | ||||
|  | ||||
|     part_detail = PartBriefSerializer(source='part', many=False, read_only=True) | ||||
|  | ||||
| @@ -204,7 +206,7 @@ class SupplierPartSerializer(InvenTreeModelSerializer): | ||||
|     pretty_name = serializers.CharField(read_only=True) | ||||
|  | ||||
|     def __init__(self, *args, **kwargs): | ||||
|  | ||||
|         """Initialize this serializer with extra detail fields as required""" | ||||
|         part_detail = kwargs.pop('part_detail', True) | ||||
|         supplier_detail = kwargs.pop('supplier_detail', True) | ||||
|         manufacturer_detail = kwargs.pop('manufacturer_detail', True) | ||||
| @@ -234,6 +236,8 @@ class SupplierPartSerializer(InvenTreeModelSerializer): | ||||
|     manufacturer_part_detail = ManufacturerPartSerializer(source='manufacturer_part', read_only=True) | ||||
|  | ||||
|     class Meta: | ||||
|         """Metaclass options.""" | ||||
|  | ||||
|         model = SupplierPart | ||||
|         fields = [ | ||||
|             'description', | ||||
| @@ -255,8 +259,7 @@ class SupplierPartSerializer(InvenTreeModelSerializer): | ||||
|         ] | ||||
|  | ||||
|     def create(self, validated_data): | ||||
|         """ Extract manufacturer data and process ManufacturerPart """ | ||||
|  | ||||
|         """Extract manufacturer data and process ManufacturerPart.""" | ||||
|         # Create SupplierPart | ||||
|         supplier_part = super().create(validated_data) | ||||
|  | ||||
| @@ -275,7 +278,7 @@ class SupplierPartSerializer(InvenTreeModelSerializer): | ||||
|  | ||||
|  | ||||
| class SupplierPriceBreakSerializer(InvenTreeModelSerializer): | ||||
|     """ Serializer for SupplierPriceBreak object """ | ||||
|     """Serializer for SupplierPriceBreak object.""" | ||||
|  | ||||
|     quantity = InvenTreeDecimalField() | ||||
|  | ||||
| @@ -292,6 +295,8 @@ class SupplierPriceBreakSerializer(InvenTreeModelSerializer): | ||||
|     ) | ||||
|  | ||||
|     class Meta: | ||||
|         """Metaclass options.""" | ||||
|  | ||||
|         model = SupplierPriceBreak | ||||
|         fields = [ | ||||
|             'pk', | ||||
|   | ||||
| @@ -1,3 +1,5 @@ | ||||
| """Unit testing for the company app API functions""" | ||||
|  | ||||
| from django.urls import reverse | ||||
|  | ||||
| from rest_framework import status | ||||
| @@ -8,9 +10,7 @@ from .models import Company | ||||
|  | ||||
|  | ||||
| class CompanyTest(InvenTreeAPITestCase): | ||||
|     """ | ||||
|     Series of tests for the Company DRF API | ||||
|     """ | ||||
|     """Series of tests for the Company DRF API.""" | ||||
|  | ||||
|     roles = [ | ||||
|         'purchase_order.add', | ||||
| @@ -18,7 +18,7 @@ class CompanyTest(InvenTreeAPITestCase): | ||||
|     ] | ||||
|  | ||||
|     def setUp(self): | ||||
|  | ||||
|         """Perform initialization for the unit test class""" | ||||
|         super().setUp() | ||||
|  | ||||
|         self.acme = Company.objects.create(name='ACME', description='Supplier', is_customer=False, is_supplier=True) | ||||
| @@ -26,6 +26,7 @@ class CompanyTest(InvenTreeAPITestCase): | ||||
|         Company.objects.create(name='Sippy Cup Emporium', description='Another supplier') | ||||
|  | ||||
|     def test_company_list(self): | ||||
|         """Test the list API endpoint for the Company model""" | ||||
|         url = reverse('api-company-list') | ||||
|  | ||||
|         # There should be three companies | ||||
| @@ -45,10 +46,7 @@ class CompanyTest(InvenTreeAPITestCase): | ||||
|         self.assertEqual(len(response.data), 2) | ||||
|  | ||||
|     def test_company_detail(self): | ||||
|         """ | ||||
|         Tests for the Company detail endpoint | ||||
|         """ | ||||
|  | ||||
|         """Tests for the Company detail endpoint.""" | ||||
|         url = reverse('api-company-detail', kwargs={'pk': self.acme.pk}) | ||||
|         response = self.get(url) | ||||
|  | ||||
| @@ -71,20 +69,14 @@ class CompanyTest(InvenTreeAPITestCase): | ||||
|         self.assertEqual(response.data['currency'], 'NZD') | ||||
|  | ||||
|     def test_company_search(self): | ||||
|         """ | ||||
|         Test search functionality in company list | ||||
|         """ | ||||
|  | ||||
|         """Test search functionality in company list.""" | ||||
|         url = reverse('api-company-list') | ||||
|         data = {'search': 'cup'} | ||||
|         response = self.get(url, data) | ||||
|         self.assertEqual(len(response.data), 2) | ||||
|  | ||||
|     def test_company_create(self): | ||||
|         """ | ||||
|         Test that we can create a company via the API! | ||||
|         """ | ||||
|  | ||||
|         """Test that we can create a company via the API!""" | ||||
|         url = reverse('api-company-list') | ||||
|  | ||||
|         # Name is required | ||||
| @@ -146,9 +138,7 @@ class CompanyTest(InvenTreeAPITestCase): | ||||
|  | ||||
|  | ||||
| class ManufacturerTest(InvenTreeAPITestCase): | ||||
|     """ | ||||
|     Series of tests for the Manufacturer DRF API | ||||
|     """ | ||||
|     """Series of tests for the Manufacturer DRF API.""" | ||||
|  | ||||
|     fixtures = [ | ||||
|         'category', | ||||
| @@ -164,6 +154,7 @@ class ManufacturerTest(InvenTreeAPITestCase): | ||||
|     ] | ||||
|  | ||||
|     def test_manufacturer_part_list(self): | ||||
|         """Test the ManufacturerPart API list functionality""" | ||||
|         url = reverse('api-manufacturer-part-list') | ||||
|  | ||||
|         # There should be three manufacturer parts | ||||
| @@ -191,9 +182,7 @@ class ManufacturerTest(InvenTreeAPITestCase): | ||||
|         self.assertEqual(len(response.data), 2) | ||||
|  | ||||
|     def test_manufacturer_part_detail(self): | ||||
|         """ | ||||
|         Tests for the ManufacturerPart detail endpoint | ||||
|         """ | ||||
|         """Tests for the ManufacturerPart detail endpoint.""" | ||||
|         url = reverse('api-manufacturer-part-detail', kwargs={'pk': 1}) | ||||
|  | ||||
|         response = self.get(url) | ||||
| @@ -210,13 +199,14 @@ class ManufacturerTest(InvenTreeAPITestCase): | ||||
|         self.assertEqual(response.data['MPN'], 'MPN-TEST-123') | ||||
|  | ||||
|     def test_manufacturer_part_search(self): | ||||
|         # Test search functionality in manufacturer list | ||||
|         """Test search functionality in manufacturer list""" | ||||
|         url = reverse('api-manufacturer-part-list') | ||||
|         data = {'search': 'MPN'} | ||||
|         response = self.get(url, data) | ||||
|         self.assertEqual(len(response.data), 3) | ||||
|  | ||||
|     def test_supplier_part_create(self): | ||||
|         """Test a SupplierPart can be created via the API""" | ||||
|         url = reverse('api-supplier-part-list') | ||||
|  | ||||
|         # Create a manufacturer part | ||||
|   | ||||
| @@ -1,6 +1,4 @@ | ||||
| """ | ||||
| Tests for the company model database migrations | ||||
| """ | ||||
| """Tests for the company model database migrations.""" | ||||
|  | ||||
| from django_test_migrations.contrib.unittest_case import MigratorTestCase | ||||
|  | ||||
| @@ -8,15 +6,13 @@ from InvenTree import helpers | ||||
|  | ||||
|  | ||||
| class TestForwardMigrations(MigratorTestCase): | ||||
|     """Unit testing class for testing 'company' app migrations""" | ||||
|  | ||||
|     migrate_from = ('company', helpers.getOldestMigrationFile('company')) | ||||
|     migrate_to = ('company', helpers.getNewestMigrationFile('company')) | ||||
|  | ||||
|     def prepare(self): | ||||
|         """ | ||||
|         Create some simple Company data, and ensure that it migrates OK | ||||
|         """ | ||||
|  | ||||
|         """Create some simple Company data, and ensure that it migrates OK.""" | ||||
|         Company = self.old_state.apps.get_model('company', 'company') | ||||
|  | ||||
|         Company.objects.create( | ||||
| @@ -26,29 +22,25 @@ class TestForwardMigrations(MigratorTestCase): | ||||
|         ) | ||||
|  | ||||
|     def test_migrations(self): | ||||
|  | ||||
|         """Test the database state after applying all migrations""" | ||||
|         Company = self.new_state.apps.get_model('company', 'company') | ||||
|  | ||||
|         self.assertEqual(Company.objects.count(), 1) | ||||
|  | ||||
|  | ||||
| class TestManufacturerField(MigratorTestCase): | ||||
|     """ | ||||
|     Tests for migration 0019 which migrates from old 'manufacturer_name' field to new 'manufacturer' field | ||||
|     """ | ||||
|     """Tests for migration 0019 which migrates from old 'manufacturer_name' field to new 'manufacturer' field.""" | ||||
|  | ||||
|     migrate_from = ('company', '0018_supplierpart_manufacturer') | ||||
|     migrate_to = ('company', '0019_auto_20200413_0642') | ||||
|  | ||||
|     def prepare(self): | ||||
|         """ | ||||
|         Prepare the database by adding some test data 'before' the change: | ||||
|         """Prepare the database by adding some test data 'before' the change: | ||||
|  | ||||
|         - Part object | ||||
|         - Company object (supplier) | ||||
|         - SupplierPart object | ||||
|         """ | ||||
|  | ||||
|         Part = self.old_state.apps.get_model('part', 'part') | ||||
|         Company = self.old_state.apps.get_model('company', 'company') | ||||
|         SupplierPart = self.old_state.apps.get_model('company', 'supplierpart') | ||||
| @@ -85,10 +77,7 @@ class TestManufacturerField(MigratorTestCase): | ||||
|         self.assertEqual(Company.objects.count(), 1) | ||||
|  | ||||
|     def test_company_objects(self): | ||||
|         """ | ||||
|         Test that the new companies have been created successfully | ||||
|         """ | ||||
|  | ||||
|         """Test that the new companies have been created successfully.""" | ||||
|         # Two additional company objects should have been created | ||||
|         Company = self.new_state.apps.get_model('company', 'company') | ||||
|         self.assertEqual(Company.objects.count(), 3) | ||||
| @@ -108,22 +97,18 @@ class TestManufacturerField(MigratorTestCase): | ||||
|  | ||||
|  | ||||
| class TestManufacturerPart(MigratorTestCase): | ||||
|     """ | ||||
|     Tests for migration 0034-0037 which added and transitioned to the ManufacturerPart model | ||||
|     """ | ||||
|     """Tests for migration 0034-0037 which added and transitioned to the ManufacturerPart model.""" | ||||
|  | ||||
|     migrate_from = ('company', '0033_auto_20210410_1528') | ||||
|     migrate_to = ('company', '0037_supplierpart_update_3') | ||||
|  | ||||
|     def prepare(self): | ||||
|         """ | ||||
|         Prepare the database by adding some test data 'before' the change: | ||||
|         """Prepare the database by adding some test data 'before' the change: | ||||
|  | ||||
|         - Part object | ||||
|         - Company object (supplier) | ||||
|         - SupplierPart object | ||||
|         """ | ||||
|  | ||||
|         Part = self.old_state.apps.get_model('part', 'part') | ||||
|         Company = self.old_state.apps.get_model('company', 'company') | ||||
|         SupplierPart = self.old_state.apps.get_model('company', 'supplierpart') | ||||
| @@ -214,10 +199,7 @@ class TestManufacturerPart(MigratorTestCase): | ||||
|         ) | ||||
|  | ||||
|     def test_manufacturer_part_objects(self): | ||||
|         """ | ||||
|         Test that the new companies have been created successfully | ||||
|         """ | ||||
|  | ||||
|         """Test that the new companies have been created successfully.""" | ||||
|         # Check on the SupplierPart objects | ||||
|         SupplierPart = self.new_state.apps.get_model('company', 'supplierpart') | ||||
|  | ||||
| @@ -238,16 +220,13 @@ class TestManufacturerPart(MigratorTestCase): | ||||
|  | ||||
|  | ||||
| class TestCurrencyMigration(MigratorTestCase): | ||||
|     """ | ||||
|     Tests for upgrade from basic currency support to django-money | ||||
|     """ | ||||
|     """Tests for upgrade from basic currency support to django-money.""" | ||||
|  | ||||
|     migrate_from = ('company', '0025_auto_20201110_1001') | ||||
|     migrate_to = ('company', '0026_auto_20201110_1011') | ||||
|  | ||||
|     def prepare(self): | ||||
|         """ | ||||
|         Prepare some data: | ||||
|         """Prepare some data: | ||||
|  | ||||
|         - A part to buy | ||||
|         - A supplier to buy from | ||||
| @@ -255,7 +234,6 @@ class TestCurrencyMigration(MigratorTestCase): | ||||
|         - Multiple currency objects | ||||
|         - Multiple supplier price breaks | ||||
|         """ | ||||
|  | ||||
|         Part = self.old_state.apps.get_model('part', 'part') | ||||
|  | ||||
|         part = Part.objects.create( | ||||
| @@ -293,7 +271,7 @@ class TestCurrencyMigration(MigratorTestCase): | ||||
|             self.assertIsNone(pb.price) | ||||
|  | ||||
|     def test_currency_migration(self): | ||||
|  | ||||
|         """Test database state after applying migrations""" | ||||
|         PB = self.new_state.apps.get_model('company', 'supplierpricebreak') | ||||
|  | ||||
|         for pb in PB.objects.all(): | ||||
|   | ||||
| @@ -1,11 +1,12 @@ | ||||
| """ Unit tests for Company views (see views.py) """ | ||||
| """Unit tests for Company views (see views.py)""" | ||||
|  | ||||
| from django.urls import reverse | ||||
|  | ||||
| from InvenTree.helpers import InvenTreeTestCase | ||||
|  | ||||
|  | ||||
| class CompanyViewTestBase(InvenTreeTestCase): | ||||
| class CompanyViewTest(InvenTreeTestCase): | ||||
|     """Tests for various 'Company' views.""" | ||||
|  | ||||
|     fixtures = [ | ||||
|         'category', | ||||
| @@ -18,40 +19,29 @@ class CompanyViewTestBase(InvenTreeTestCase): | ||||
|  | ||||
|     roles = 'all' | ||||
|  | ||||
|  | ||||
| class CompanyViewTest(CompanyViewTestBase): | ||||
|     """ | ||||
|     Tests for various 'Company' views | ||||
|     """ | ||||
|  | ||||
|     def test_company_index(self): | ||||
|         """ Test the company index """ | ||||
|  | ||||
|         """Test the company index.""" | ||||
|         response = self.client.get(reverse('company-index')) | ||||
|         self.assertEqual(response.status_code, 200) | ||||
|  | ||||
|     def test_manufacturer_index(self): | ||||
|         """ Test the manufacturer index """ | ||||
|  | ||||
|         """Test the manufacturer index.""" | ||||
|         response = self.client.get(reverse('manufacturer-index')) | ||||
|         self.assertEqual(response.status_code, 200) | ||||
|  | ||||
|     def test_customer_index(self): | ||||
|         """ Test the customer index """ | ||||
|  | ||||
|         """Test the customer index.""" | ||||
|         response = self.client.get(reverse('customer-index')) | ||||
|         self.assertEqual(response.status_code, 200) | ||||
|  | ||||
|     def test_manufacturer_part_detail_view(self): | ||||
|         """ Test the manufacturer part detail view """ | ||||
|  | ||||
|         """Test the manufacturer part detail view.""" | ||||
|         response = self.client.get(reverse('manufacturer-part-detail', kwargs={'pk': 1})) | ||||
|         self.assertEqual(response.status_code, 200) | ||||
|         self.assertContains(response, 'MPN123') | ||||
|  | ||||
|     def test_supplier_part_detail_view(self): | ||||
|         """ Test the supplier part detail view """ | ||||
|  | ||||
|         """Test the supplier part detail view.""" | ||||
|         response = self.client.get(reverse('supplier-part-detail', kwargs={'pk': 10})) | ||||
|         self.assertEqual(response.status_code, 200) | ||||
|         self.assertContains(response, 'MPN456-APPEL') | ||||
|   | ||||
| @@ -1,3 +1,5 @@ | ||||
| """Unit tests for the models in the 'company' app""" | ||||
|  | ||||
| import os | ||||
| from decimal import Decimal | ||||
|  | ||||
| @@ -11,6 +13,7 @@ from .models import (Company, Contact, ManufacturerPart, SupplierPart, | ||||
|  | ||||
|  | ||||
| class CompanySimpleTest(TestCase): | ||||
|     """Unit tests for the Company model""" | ||||
|  | ||||
|     fixtures = [ | ||||
|         'company', | ||||
| @@ -24,6 +27,7 @@ class CompanySimpleTest(TestCase): | ||||
|     ] | ||||
|  | ||||
|     def setUp(self): | ||||
|         """Perform initialization for the tests in this class""" | ||||
|         Company.objects.create(name='ABC Co.', | ||||
|                                description='Seller of ABC products', | ||||
|                                website='www.abc-sales.com', | ||||
| @@ -37,15 +41,18 @@ class CompanySimpleTest(TestCase): | ||||
|         self.zergm312 = SupplierPart.objects.get(SKU='ZERGM312') | ||||
|  | ||||
|     def test_company_model(self): | ||||
|         """Tests for the company model data""" | ||||
|         c = Company.objects.get(name='ABC Co.') | ||||
|         self.assertEqual(c.name, 'ABC Co.') | ||||
|         self.assertEqual(str(c), 'ABC Co. - Seller of ABC products') | ||||
|  | ||||
|     def test_company_url(self): | ||||
|         """Test the detail URL for a company""" | ||||
|         c = Company.objects.get(pk=1) | ||||
|         self.assertEqual(c.get_absolute_url(), '/company/1/') | ||||
|  | ||||
|     def test_image_renamer(self): | ||||
|         """Test the company image upload functionality""" | ||||
|         c = Company.objects.get(pk=1) | ||||
|         rn = rename_company_image(c, 'test.png') | ||||
|         self.assertEqual(rn, 'company_images' + os.path.sep + 'company_1_img.png') | ||||
| @@ -53,23 +60,8 @@ class CompanySimpleTest(TestCase): | ||||
|         rn = rename_company_image(c, 'test2') | ||||
|         self.assertEqual(rn, 'company_images' + os.path.sep + 'company_1_img') | ||||
|  | ||||
|     def test_part_count(self): | ||||
|  | ||||
|         acme = Company.objects.get(pk=1) | ||||
|         appel = Company.objects.get(pk=2) | ||||
|         zerg = Company.objects.get(pk=3) | ||||
|  | ||||
|         self.assertTrue(acme.has_parts) | ||||
|         self.assertEqual(acme.supplied_part_count, 4) | ||||
|  | ||||
|         self.assertTrue(appel.has_parts) | ||||
|         self.assertEqual(appel.supplied_part_count, 4) | ||||
|  | ||||
|         self.assertTrue(zerg.has_parts) | ||||
|         self.assertEqual(zerg.supplied_part_count, 2) | ||||
|  | ||||
|     def test_price_breaks(self): | ||||
|  | ||||
|         """Unit tests for price breaks""" | ||||
|         self.assertTrue(self.acme0001.has_price_breaks) | ||||
|         self.assertTrue(self.acme0002.has_price_breaks) | ||||
|         self.assertTrue(self.zergm312.has_price_breaks) | ||||
| @@ -81,8 +73,7 @@ class CompanySimpleTest(TestCase): | ||||
|         self.assertEqual(self.zergm312.price_breaks.count(), 2) | ||||
|  | ||||
|     def test_quantity_pricing(self): | ||||
|         """ Simple test for quantity pricing """ | ||||
|  | ||||
|         """Simple test for quantity pricing.""" | ||||
|         p = self.acme0001.get_price | ||||
|         self.assertEqual(p(1), 10) | ||||
|         self.assertEqual(p(4), 40) | ||||
| @@ -99,6 +90,7 @@ class CompanySimpleTest(TestCase): | ||||
|         self.assertEqual(p(55), 68.75) | ||||
|  | ||||
|     def test_part_pricing(self): | ||||
|         """Unit tests for supplier part pricing""" | ||||
|         m2x4 = Part.objects.get(name='M2x4 LPHS') | ||||
|  | ||||
|         self.assertEqual(m2x4.get_price_info(5.5), "38.5 - 41.25") | ||||
| @@ -116,10 +108,7 @@ class CompanySimpleTest(TestCase): | ||||
|         self.assertIsNotNone(m3x12.get_price_info(50)) | ||||
|  | ||||
|     def test_currency_validation(self): | ||||
|         """ | ||||
|         Test validation for currency selection | ||||
|         """ | ||||
|  | ||||
|         """Test validation for currency selection.""" | ||||
|         # Create a company with a valid currency code (should pass) | ||||
|         company = Company.objects.create( | ||||
|             name='Test', | ||||
| @@ -141,8 +130,10 @@ class CompanySimpleTest(TestCase): | ||||
|  | ||||
|  | ||||
| class ContactSimpleTest(TestCase): | ||||
|     """Unit tests for the Contact model""" | ||||
|  | ||||
|     def setUp(self): | ||||
|         """Initialization for the tests in this class""" | ||||
|         # Create a simple company | ||||
|         self.c = Company.objects.create(name='Test Corp.', description='We make stuff good') | ||||
|  | ||||
| @@ -152,15 +143,18 @@ class ContactSimpleTest(TestCase): | ||||
|         Contact.objects.create(name='Sally Smith', company=self.c) | ||||
|  | ||||
|     def test_exists(self): | ||||
|         """Test that contacts exist""" | ||||
|         self.assertEqual(Contact.objects.count(), 3) | ||||
|  | ||||
|     def test_delete(self): | ||||
|         """Test deletion of a Contact instance""" | ||||
|         # Remove the parent company | ||||
|         Company.objects.get(pk=self.c.pk).delete() | ||||
|         self.assertEqual(Contact.objects.count(), 0) | ||||
|  | ||||
|  | ||||
| class ManufacturerPartSimpleTest(TestCase): | ||||
|     """Unit tests for the ManufacturerPart model""" | ||||
|  | ||||
|     fixtures = [ | ||||
|         'category', | ||||
| @@ -171,6 +165,8 @@ class ManufacturerPartSimpleTest(TestCase): | ||||
|     ] | ||||
|  | ||||
|     def setUp(self): | ||||
|         """Initialization for the unit tests in this class""" | ||||
|  | ||||
|         # Create a manufacturer part | ||||
|         self.part = Part.objects.get(pk=1) | ||||
|         manufacturer = Company.objects.get(pk=1) | ||||
| @@ -193,6 +189,7 @@ class ManufacturerPartSimpleTest(TestCase): | ||||
|         supplier_part.save() | ||||
|  | ||||
|     def test_exists(self): | ||||
|         """That that a ManufacturerPart has been created""" | ||||
|         self.assertEqual(ManufacturerPart.objects.count(), 4) | ||||
|  | ||||
|         # Check that manufacturer part was created from supplier part creation | ||||
| @@ -200,7 +197,7 @@ class ManufacturerPartSimpleTest(TestCase): | ||||
|         self.assertEqual(manufacturer_parts.count(), 1) | ||||
|  | ||||
|     def test_delete(self): | ||||
|         # Remove a part | ||||
|         """Test deletion of a ManufacturerPart""" | ||||
|         Part.objects.get(pk=self.part.id).delete() | ||||
|         # Check that ManufacturerPart was deleted | ||||
|         self.assertEqual(ManufacturerPart.objects.count(), 3) | ||||
|   | ||||
| @@ -1,6 +1,4 @@ | ||||
| """ | ||||
| URL lookup for Company app | ||||
| """ | ||||
| """URL lookup for Company app.""" | ||||
|  | ||||
| from django.urls import include, re_path | ||||
|  | ||||
|   | ||||
| @@ -1,6 +1,4 @@ | ||||
| """ | ||||
| Django views for interacting with Company app | ||||
| """ | ||||
| """Django views for interacting with Company app.""" | ||||
|  | ||||
| import io | ||||
|  | ||||
| @@ -20,8 +18,7 @@ from .models import Company, ManufacturerPart, SupplierPart | ||||
|  | ||||
|  | ||||
| class CompanyIndex(InvenTreeRoleMixin, ListView): | ||||
|     """ View for displaying list of companies | ||||
|     """ | ||||
|     """View for displaying list of companies.""" | ||||
|  | ||||
|     model = Company | ||||
|     template_name = 'company/index.html' | ||||
| @@ -30,6 +27,7 @@ class CompanyIndex(InvenTreeRoleMixin, ListView): | ||||
|     permission_required = 'company.view_company' | ||||
|  | ||||
|     def get_context_data(self, **kwargs): | ||||
|         """Add extra context data to the company index page""" | ||||
|  | ||||
|         ctx = super().get_context_data(**kwargs) | ||||
|  | ||||
| @@ -80,7 +78,7 @@ class CompanyIndex(InvenTreeRoleMixin, ListView): | ||||
|         return ctx | ||||
|  | ||||
|     def get_queryset(self): | ||||
|         """ Retrieve the Company queryset based on HTTP request parameters. | ||||
|         """Retrieve the Company queryset based on HTTP request parameters. | ||||
|  | ||||
|         - supplier: Filter by supplier | ||||
|         - customer: Filter by customer | ||||
| @@ -97,23 +95,16 @@ class CompanyIndex(InvenTreeRoleMixin, ListView): | ||||
|  | ||||
|  | ||||
| class CompanyDetail(InvenTreePluginViewMixin, DetailView): | ||||
|     """ Detail view for Company object """ | ||||
|     """Detail view for Company object.""" | ||||
|     context_obect_name = 'company' | ||||
|     template_name = 'company/detail.html' | ||||
|     queryset = Company.objects.all() | ||||
|     model = Company | ||||
|     permission_required = 'company.view_company' | ||||
|  | ||||
|     def get_context_data(self, **kwargs): | ||||
|         ctx = super().get_context_data(**kwargs) | ||||
|  | ||||
|         return ctx | ||||
|  | ||||
|  | ||||
| class CompanyImageDownloadFromURL(AjaxUpdateView): | ||||
|     """ | ||||
|     View for downloading an image from a provided URL | ||||
|     """ | ||||
|     """View for downloading an image from a provided URL.""" | ||||
|  | ||||
|     model = Company | ||||
|     ajax_template_name = 'image_download.html' | ||||
| @@ -121,9 +112,7 @@ class CompanyImageDownloadFromURL(AjaxUpdateView): | ||||
|     ajax_form_title = _('Download Image') | ||||
|  | ||||
|     def validate(self, company, form): | ||||
|         """ | ||||
|         Validate that the image data are correct | ||||
|         """ | ||||
|         """Validate that the image data are correct.""" | ||||
|         # First ensure that the normal validation routines pass | ||||
|         if not form.is_valid(): | ||||
|             return | ||||
| @@ -167,9 +156,7 @@ class CompanyImageDownloadFromURL(AjaxUpdateView): | ||||
|             return | ||||
|  | ||||
|     def save(self, company, form, **kwargs): | ||||
|         """ | ||||
|         Save the downloaded image to the company | ||||
|         """ | ||||
|         """Save the downloaded image to the company.""" | ||||
|         fmt = self.image.format | ||||
|  | ||||
|         if not fmt: | ||||
| @@ -189,28 +176,18 @@ class CompanyImageDownloadFromURL(AjaxUpdateView): | ||||
|  | ||||
|  | ||||
| class ManufacturerPartDetail(InvenTreePluginViewMixin, DetailView): | ||||
|     """ Detail view for ManufacturerPart """ | ||||
|     """Detail view for ManufacturerPart.""" | ||||
|     model = ManufacturerPart | ||||
|     template_name = 'company/manufacturer_part_detail.html' | ||||
|     context_object_name = 'part' | ||||
|     queryset = ManufacturerPart.objects.all() | ||||
|     permission_required = 'purchase_order.view' | ||||
|  | ||||
|     def get_context_data(self, **kwargs): | ||||
|         ctx = super().get_context_data(**kwargs) | ||||
|  | ||||
|         return ctx | ||||
|  | ||||
|  | ||||
| class SupplierPartDetail(InvenTreePluginViewMixin, DetailView): | ||||
|     """ Detail view for SupplierPart """ | ||||
|     """Detail view for SupplierPart.""" | ||||
|     model = SupplierPart | ||||
|     template_name = 'company/supplier_part_detail.html' | ||||
|     context_object_name = 'part' | ||||
|     queryset = SupplierPart.objects.all() | ||||
|     permission_required = 'purchase_order.view' | ||||
|  | ||||
|     def get_context_data(self, **kwargs): | ||||
|         ctx = super().get_context_data(**kwargs) | ||||
|  | ||||
|         return ctx | ||||
|   | ||||
		Reference in New Issue
	
	Block a user