from django import forms from django.contrib.auth import get_user_model from django.core.exceptions import ValidationError from django.forms import widgets from parts import models as parts_models from shimatta_modules.EngineeringNumberConverter import EngineeringNumberConverter import uuid from django.urls import reverse from .qr_parser import QrCodeValidator from crispy_forms.helper import FormHelper from crispy_forms.layout import Layout, Row, Column class AutoCompleteWidget(widgets.Input): template_name = 'widgets/autocomplete-foreign-key.html' def __init__(self, api_search_url, image_field_name, foreign_model, name_field_name, prepend=None, *args, **kwargs): super().__init__(*args, **kwargs) self.image_field_name = image_field_name self.foreign_model = foreign_model self.api_search_url = api_search_url self.name_field_name = name_field_name self.prepend = prepend def get_context(self, name, value, attrs): context = super().get_context(name, value, attrs) if value is not None: try: try: my_id = uuid.UUID(value) except: my_id = int(value) instance = self.foreign_model.objects.get(id=my_id) except Exception as ex: instance = None else: instance = None image = None if instance is not None and self.image_field_name is not None: image = getattr(instance, self.image_field_name) display_name = None if instance: display_name = getattr(instance, self.name_field_name) context['custom'] = { 'search_url': reverse(self.api_search_url), 'image_field_name': self.image_field_name, 'current_instance': instance, 'image': image, 'name_field_name': self.name_field_name, 'prepend': self.prepend, 'name': display_name, } return context class AutocompleteForeingKeyField(forms.UUIDField): def __init__(self, foreign_model=None, api_search_url=None, image_field_name='image', name_field_name='name', prepend=None, **kwargs): super().__init__(**kwargs) self.widget = AutoCompleteWidget(api_search_url, image_field_name, foreign_model, name_field_name, prepend) self.foreign_model = foreign_model def clean(self, value): try: pre_cleaned_uuid = super().clean(value) except Exception as ex: try: pre_cleaned_uuid = int(value) except: raise ex if pre_cleaned_uuid is None and not self.required: return None try: obj = self.foreign_model.objects.get(id=pre_cleaned_uuid) except self.foreign_model.DoesNotExist: raise ValidationError('Given element does not exist') return obj class MyTestForm(forms.Form): pass class ChangeStorageForm(forms.Form): storage_name = forms.CharField(label="Name", initial='') verbose_name = forms.CharField(label="Verbose Name", initial='', required=False) responsible = AutocompleteForeingKeyField(api_search_url='user-list', image_field_name=None, name_field_name='username', foreign_model=get_user_model(), prepend='@') is_template = forms.BooleanField(label='is_template', required=False) class AddSubStorageForm(ChangeStorageForm): template = AutocompleteForeingKeyField(api_search_url='storage-template-list', image_field_name=None, foreign_model=parts_models.Storage, required=False) class DeleteStockForm(forms.Form): stock_uuid = forms.UUIDField() class EditWatermarkForm(forms.Form): stock_uuid = forms.UUIDField() watermark_active = forms.BooleanField(required=False) #If it is false, the webbrowser won't send it at all. Therefore we have to set it to required=False watermark = forms.IntegerField(min_value=0) def clean(self): cleaned_data = super().clean() id = cleaned_data.get("stock_uuid") if not id: raise ValidationError("No stock UUID given") stock = None try: stock = parts_models.Stock.objects.get(id=id) except: raise ValidationError("Stock with uuid %s does not exist" % (id)) cleaned_data['stock'] = stock return cleaned_data def save(self): stock = self.cleaned_data['stock'] active = self.cleaned_data['watermark_active'] watermark = self.cleaned_data['watermark'] if not active: watermark = -1 stock.watermark = watermark stock.save() class EditStockAmountForm(forms.Form): stock_uuid = forms.UUIDField() amount = forms.IntegerField(min_value=0) def clean(self): cleaned_data = super().clean() id = cleaned_data.get("stock_uuid") if not id: raise ValidationError("No stock UUID given") stock = None try: stock = parts_models.Stock.objects.get(id=id) except: raise ValidationError("Stock with uuid %s does not exist" % (id)) cleaned_data['stock'] = stock return cleaned_data def save(self, increase: bool): stock = self.cleaned_data['stock'] amount = self.cleaned_data['amount'] if not increase: amount = -amount return stock.atomic_increment(amount) class AddStockForm(forms.Form): watermark_active = forms.BooleanField(required=False) watermark = forms.IntegerField(min_value=0, required=True, initial=0) amount = forms.IntegerField(min_value=0, required=True, initial=1) component_uuid = forms.UUIDField(required=True) lot = forms.CharField(max_length=255, required=False) def clean(self): cleaned_data = super().clean() id = cleaned_data.get('component_uuid') if not id: raise ValidationError('No valid component selected!') component = None try: component = parts_models.Component.objects.get(id=id) except: raise ValidationError("Invalid component selected!") cleaned_data['component'] = component return cleaned_data def save(self, storage): component = self.cleaned_data.get('component') amount = self.cleaned_data.get('amount') watermark = -1 if self.cleaned_data.get('watermark_active'): watermark = self.cleaned_data.get('watermark') new_stock = parts_models.Stock.objects.create(storage=storage, component=component, watermark=watermark, amount=amount, lot=self.cleaned_data['lot']) new_stock.save() class ComponentForm(forms.ModelForm): manufacturer = AutocompleteForeingKeyField(api_search_url='manufacturer-list', foreign_model=parts_models.Manufacturer, required=False) component_type = AutocompleteForeingKeyField(api_search_url='componenttype-list', foreign_model=parts_models.ComponentType, name_field_name='class_name', required=False, image_field_name=None) package = AutocompleteForeingKeyField(api_search_url='package-list', foreign_model=parts_models.Package, required=False) pref_distri = AutocompleteForeingKeyField(api_search_url='distributor-list', foreign_model=parts_models.Distributor, required=False) class Meta: model = parts_models.Component fields = '__all__' class ImportComponentForm(forms.Form): csv_file = forms.FileField(label="CSV File") class PackageForm(forms.ModelForm): class Meta: model = parts_models.Package fields = '__all__' class DistributorForm(forms.ModelForm): class Meta: model = parts_models.Distributor fields = '__all__' class ManufacturerForm(forms.ModelForm): class Meta: model = parts_models.Manufacturer fields = '__all__' class DistributorNumberCreateForm(forms.ModelForm): distributor = AutocompleteForeingKeyField(api_search_url='distributor-list', foreign_model=parts_models.Distributor, required=True) class Meta: model = parts_models.DistributorNum fields = ['distributor', 'distributor_part_number'] class DistributorNumberDeleteForm(forms.Form): distributor_num = forms.UUIDField(required=True) def clean_distributor_num(self): my_uuid = self.cleaned_data['distributor_num'] try: distributor_number = parts_models.DistributorNum.objects.get(id=my_uuid) except: raise ValidationError('distributor number invalid') return distributor_number 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 = 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) package_pin_count = forms.IntegerField(min_value=0, label='Pin Count', required=False) distributor_num = forms.CharField(max_length=100, label='Distributor Part Number', required=False) distributor = AutocompleteForeingKeyField(required=False, api_search_url='distributor-list', foreign_model=parts_models.Distributor) component_type = AutocompleteForeingKeyField(required=False, api_search_url='componenttype-list', foreign_model=parts_models.ComponentType, image_field_name=None, name_field_name='class_name') manufacturer = AutocompleteForeingKeyField(required=False, api_search_url='manufacturer-list', foreign_model=parts_models.Manufacturer) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.helper = FormHelper() self.helper.form_tag = False self.helper.layout = Layout( Row( Column('name'), ), Row( Column('package'), Column('package_pin_count'), ), Row( Column('component_type'), Column('manufacturer'), ), Row( Column('distributor'), Column('distributor_num'), ), ) class ComponentParameterSearchForm(forms.Form): parameter = AutocompleteForeingKeyField(required=True, foreign_model=parts_models.ComponentParameterType, api_search_url='componentparametertype-list', image_field_name=None, name_field_name='parameter_name') value = forms.CharField(max_length=100, required=False) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.helper = FormHelper() self.helper.form_tag = False self.helper.layout = Layout( Row( Column('parameter'), Column('value') ) ) 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() ptype = data.get('parameter_type') value = data.get('value') if not ptype: raise ValidationError('No valid parameter type selected') if not value: raise ValidationError('No valid parameter value') if ptype.parameter_type == 'E' or ptype.parameter_type == 'I' or ptype.parameter_type == 'N': try: number = EngineeringNumberConverter.engineering_to_number(value) except: raise ValidationError('Cannot convert value to number') data['number_value'] = number else: pass def save(self, component): 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, 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() def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) qr_search = forms.CharField(label='qr_search', validators=[my_qr_validator])