diff --git a/shimatta_kenkyusho/parts/forms.py b/shimatta_kenkyusho/parts/forms.py index 5e1743c..44752e6 100644 --- a/shimatta_kenkyusho/parts/forms.py +++ b/shimatta_kenkyusho/parts/forms.py @@ -252,15 +252,19 @@ class DistributorNumberDeleteForm(forms.Form): class ComponentParameterDeleteForm(forms.Form): param_num = forms.UUIDField(required=True) + model = parts_models.ComponentParameter def clean_param_num(self): my_uuid = self.cleaned_data['param_num'] try: - param = parts_models.ComponentParameter.objects.get(id=my_uuid) + param = self.model.objects.get(id=my_uuid) except: raise ValidationError('Parameter Number Invalid') return param +class PackageParameterDeleteForm(ComponentParameterDeleteForm): + model = parts_models.PackageParameter + class AdvancedComponentSearchForm(forms.Form): name = forms.CharField(max_length=255, label='Component Name', required=False) package = AutocompleteForeingKeyField(required=False, api_search_url='package-list', foreign_model=parts_models.Package) @@ -309,6 +313,7 @@ class ComponentParameterSearchForm(forms.Form): class ComponentParameterCreateForm(forms.Form): parameter_type = AutocompleteForeingKeyField(required=True, foreign_model=parts_models.ComponentParameterType, api_search_url='componentparametertype-list', image_field_name=None, name_field_name='descriptive_name') value = forms.CharField(required=True, max_length=256) + model = parts_models.ComponentParameter def clean(self): data = super().clean() @@ -338,7 +343,20 @@ class ComponentParameterCreateForm(forms.Form): else: text_value = '' value = self.cleaned_data['number_value'] - parts_models.ComponentParameter.objects.create(parameter_type=param_type, component=component, value=value, text_value=text_value) + self.model.objects.create(parameter_type=param_type, component=component, value=value, text_value=text_value) + +class PackageParameterCreateForm(ComponentParameterCreateForm): + model = parts_models.PackageParameter + + def save(self, package): + param_type = self.cleaned_data['parameter_type'] + if param_type.parameter_type == 'F': + text_value = self.cleaned_data['value'] + value = 0 + else: + text_value = '' + value = self.cleaned_data['number_value'] + self.model.objects.create(parameter_type=param_type, package=package, value=value, text_value=text_value) class QrSearchForm(forms.Form): my_qr_validator = QrCodeValidator() diff --git a/shimatta_kenkyusho/parts/management/commands/consolidate_component_package_parameters.py b/shimatta_kenkyusho/parts/management/commands/consolidate_component_package_parameters.py new file mode 100644 index 0000000..e66ca5a --- /dev/null +++ b/shimatta_kenkyusho/parts/management/commands/consolidate_component_package_parameters.py @@ -0,0 +1,37 @@ +from django.core.management.base import BaseCommand, CommandParser +from django.contrib.auth import get_user_model +from parts.models import Component, ComponentParameter, ComponentParameterType, PackageParameter, Package + +class Command(BaseCommand): + help = "Remove component parameters, that are also set on the package with the same value" + + def add_arguments(self, parser: CommandParser): + parser.add_argument('--dry-run', + help='Do not perform parameter deletion. Print only', + action='store_true') + + def handle(self, *args, **options): + # Get all components with set packages. Ignore the ones without packages + all_comps = Component.objects.exclude(package__isnull=True) + + for component in all_comps: + package_parameters = PackageParameter.objects.filter(package=component.package) + component_parameters = ComponentParameter.objects.filter(component=component) + package_param_ids = package_parameters.values_list('parameter_type_id', flat=True) + component_param_ids = component_parameters.values_list('parameter_type_id', flat=True) + + self.stdout.write(f'Comp: {str(component)} Found {len(component_param_ids)} different parameters') + self.stdout.write(f'\tPackage: {str(component.package)} Found {len(package_param_ids)} different parameters') + + commontypes = ctypes = ComponentParameterType.objects.filter(id__in=component_param_ids).filter(id__in=package_param_ids) + self.stdout.write(f'\tCommon parameter count: {len(commontypes)}') + + # Check if values are the same when rendered as a string. This avoids float comparison problems + for common_type in commontypes: + s1 = package_parameters.filter(parameter_type=common_type).first().resolved_value_as_string() + comp_param = component_parameters.filter(parameter_type=common_type).first() + s2 = comp_param.resolved_value_as_string() + if s1 == s2: + self.stdout.write(f'\tParameter {common_type.parameter_name} is the same value for component and package: {s1}. Removing from component') + if not options['dry_run']: + comp_param.delete() \ No newline at end of file diff --git a/shimatta_kenkyusho/parts/views/component_views.py b/shimatta_kenkyusho/parts/views/component_views.py index 76eed61..d092c84 100644 --- a/shimatta_kenkyusho/parts/views/component_views.py +++ b/shimatta_kenkyusho/parts/views/component_views.py @@ -8,7 +8,7 @@ from django.db.models import Q from django.forms import formset_factory from django.db import IntegrityError from django.db.models import ProtectedError -from ..models import Stock, Component, ComponentParameter, DistributorNum +from ..models import Stock, Component, ComponentParameter, DistributorNum, PackageParameter from ..forms import * from .component_import import import_components_from_csv from .generic_views import BaseTemplateMixin @@ -174,6 +174,8 @@ class ComponentDetailView(LoginRequiredMixin, BaseTemplateMixin, DetailView): 'distributor__name') context['parameters'] = ComponentParameter.objects.filter(component=self.object).order_by( 'parameter_type__parameter_name') + context['package_parameters'] = PackageParameter.objects.filter(package=self.object.package).order_by( + 'parameter_type__parameter_name') return context diff --git a/shimatta_kenkyusho/parts/views/package_views.py b/shimatta_kenkyusho/parts/views/package_views.py index 37ad2e7..2615581 100644 --- a/shimatta_kenkyusho/parts/views/package_views.py +++ b/shimatta_kenkyusho/parts/views/package_views.py @@ -5,7 +5,7 @@ from django.core.paginator import Paginator from django.db.models import ProtectedError from django.db.models import Q from ..forms import * -from ..models import Package +from ..models import Package, PackageParameter from .generic_views import BaseTemplateMixin class PackageView(LoginRequiredMixin, BaseTemplateMixin, TemplateView): @@ -82,6 +82,9 @@ class PackageDetailView(LoginRequiredMixin, BaseTemplateMixin, DetailView): context = super().get_context_data(**kwargs) context['package'] = self.object context['edit_form'] = PackageForm(instance=self.object) + context['new_param_form'] = PackageParameterCreateForm() + context['parameters'] = PackageParameter.objects.filter(package=self.object).order_by( + 'parameter_type__parameter_name') return context @@ -116,6 +119,27 @@ class PackageDetailView(LoginRequiredMixin, BaseTemplateMixin, DetailView): if not edit_form.is_valid(): context['edit_form'] = edit_form return self.render_to_response(context) + + def handle_submit_delete_param_post(self, request, **kwargs): + form = PackageParameterDeleteForm(data=request.POST) + if form.is_valid(): + form.cleaned_data['param_num'].delete() + + context = self.get_context_data(**kwargs) + return self.render_to_response(context) + + def handle_submit_new_param_post(self, request, **kwargs): + form = PackageParameterCreateForm(data=request.POST) + + if form.is_valid(): + try: + form.save(self.object) + except IntegrityError: + form.add_error('__all__', 'This parameter is already set') + context = self.get_context_data(**kwargs) + if not form.is_valid(): + context['new_param_form'] = form + return self.render_to_response(context) def post(self, request, *args, **kwargs): self.object = self.get_object() @@ -124,5 +148,9 @@ class PackageDetailView(LoginRequiredMixin, BaseTemplateMixin, DetailView): return self.handle_delete_package(request) elif 'submit-pkg-edit' in request.POST: return self.edit_package(request) + elif 'submit-delete-param' in request.POST: + return self.handle_submit_delete_param_post(request, **kwargs) + elif 'submit-create-new-param' in request.POST: + return self.handle_submit_new_param_post(request, **kwargs) return super().post(request, *args, **kwargs) \ No newline at end of file diff --git a/shimatta_kenkyusho/templates/parts/components-detail.html b/shimatta_kenkyusho/templates/parts/components-detail.html index a8d2163..c565ac4 100644 --- a/shimatta_kenkyusho/templates/parts/components-detail.html +++ b/shimatta_kenkyusho/templates/parts/components-detail.html @@ -119,6 +119,19 @@ + {% for param in package_parameters %} + + +
+ {{param.parameter_type.parameter_name}} +
+ + + {{param.resolved_value_as_string}} + + from Package + + {% endfor %} {% for param in parameters %} @@ -148,6 +161,13 @@ {% endif %} {% endfor %} + {% for param in package_parameters %} + {% if param.parameter_type.parameter_description %} +
+ {{param.parameter_type.parameter_description}} +
+ {% endif %} + {% endfor %}
diff --git a/shimatta_kenkyusho/templates/parts/packages-detail.html b/shimatta_kenkyusho/templates/parts/packages-detail.html index ca00bfb..d73d461 100644 --- a/shimatta_kenkyusho/templates/parts/packages-detail.html +++ b/shimatta_kenkyusho/templates/parts/packages-detail.html @@ -26,6 +26,46 @@
+
+

Parameters

+ + + + + + + + {% for param in parameters %} + + + + + + {% endfor %} + +
ParameterValue
+
+ {{param.parameter_type.parameter_name}} +
+
+ {{param.resolved_value_as_string}} + +
+ {% csrf_token %} + + +
+
+
+ {% for param in parameters %} + {% if param.parameter_type.parameter_description %} +
+ {{param.parameter_type.parameter_description}} +
+ {% endif %} + {% endfor %} +
+
@@ -80,7 +120,7 @@ - +{% include 'parts/modals/new-component-parameter-modal.html' with component_name=object.name form=new_param_form %} {% endblock content %}