from django import forms from django.forms import inlineformset_factory from django.db.models import Q from .models import ( Inventory, InventoryItem, Product, ProductCategory, PurchaseOrder, PurchaseOrderItem, PreparationOrder, PreparationOrderItem, ProductionOrder, ProductionOrderComponent, Supplier, Warehouse, WarehouseLocation, RequestForQuote, RequestForQuoteItem, ) class PreparationOrderForm(forms.ModelForm): class Meta: model = PreparationOrder fields = ["order_number", "status", "requester", "priority", "is_loan", "estimated_return_date"] widgets = { "requester": forms.TextInput(attrs={ "class": "form-control", "placeholder": "Nom, service ou équipe à l'origine de la demande", }), "estimated_return_date": forms.DateInput(attrs={ "type": "date", "class": "form-control", }), } def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) for field_name in self.fields: if field_name != "requester": if isinstance(self.fields[field_name].widget, forms.Select): self.fields[field_name].widget.attrs['class'] = 'form-select' elif isinstance(self.fields[field_name].widget, forms.CheckboxInput): self.fields[field_name].widget.attrs['class'] = 'form-check-input' else: self.fields[field_name].widget.attrs['class'] = 'form-control' self.fields["requester"].required = False # class PreparationOrderDesignForm(forms.Form): # """Formulaire utilisé côté serveur pour valider une ligne conception.""" # design_id = forms.IntegerField() # quantity = forms.IntegerField(min_value=1, initial=1) class PreparationOrderItemForm(forms.ModelForm): class Meta: model = PreparationOrderItem fields = ["product", "quantity"] def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) if self.instance and self.instance.pk and self.instance.product: self.fields["product"].queryset = Product.objects.filter( Q(is_active=True) | Q(pk=self.instance.product.pk) ).order_by("name") else: self.fields["product"].queryset = Product.objects.filter(is_active=True).order_by("name") class RequestForQuoteForm(forms.ModelForm): class Meta: model = RequestForQuote fields = ["warehouse", "suppliers", "notes", "status"] widgets = { "warehouse": forms.Select(attrs={"class": "form-select"}), "suppliers": forms.SelectMultiple(attrs={"class": "form-select", "size": "6"}), "notes": forms.Textarea(attrs={"class": "form-control", "rows": 3}), "status": forms.Select(attrs={"class": "form-select"}), } def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.fields["suppliers"].required = False self.fields["notes"].required = False self.fields["suppliers"].queryset = Supplier.objects.filter(is_active=True).order_by("name") class RequestForQuoteItemForm(forms.ModelForm): class Meta: model = RequestForQuoteItem fields = ["product", "num_articles", "quantity_per_article", "quantity"] widgets = { "num_articles": forms.NumberInput(attrs={"class": "form-control", "min": "1", "placeholder": "ex: 10"}), "quantity_per_article": forms.NumberInput(attrs={"class": "form-control", "min": "0.001", "step": "any", "placeholder": "ex: 10"}), "quantity": forms.NumberInput(attrs={"class": "form-control", "min": "0"}), } def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.fields["num_articles"].required = False self.fields["quantity_per_article"].required = False self.fields["quantity"].required = False if not self.instance.pk: self.fields["quantity_per_article"].initial = 1 if self.instance and self.instance.pk and self.instance.product: self.fields["product"].queryset = Product.objects.filter( Q(is_active=True) | Q(pk=self.instance.product.pk) ).order_by("name") else: self.fields["product"].queryset = Product.objects.filter(is_active=True).order_by("name") def clean(self): cleaned_data = super().clean() num_articles = cleaned_data.get("num_articles") quantity_per_article = cleaned_data.get("quantity_per_article") quantity = cleaned_data.get("quantity") if num_articles and quantity_per_article: cleaned_data["quantity"] = int(num_articles * quantity_per_article) elif not quantity: raise forms.ValidationError( "Indiquez soit une quantité totale, soit un nombre d'articles et une quantité par article." ) return cleaned_data RequestForQuoteItemFormSet = inlineformset_factory( RequestForQuote, RequestForQuoteItem, form=RequestForQuoteItemForm, extra=1, can_delete=True, ) class PurchaseOrderForm(forms.ModelForm): class Meta: model = PurchaseOrder fields = ["supplier", "warehouse", "status", "request_for_quote"] widgets = { "request_for_quote": forms.HiddenInput(), } class PurchaseOrderItemForm(forms.ModelForm): class Meta: model = PurchaseOrderItem fields = ["product", "location", "num_articles", "quantity_per_article", "quantity", "unit_price", "vat_rate"] widgets = { "num_articles": forms.NumberInput(attrs={"class": "form-control", "min": "1", "placeholder": "ex: 10"}), "quantity_per_article": forms.NumberInput(attrs={"class": "form-control", "min": "0.001", "step": "any", "placeholder": "ex: 10"}), "quantity": forms.NumberInput(attrs={"class": "form-control", "min": "0"}), "unit_price": forms.NumberInput(attrs={"class": "form-control", "min": "0", "step": "0.01", "placeholder": "ex: 47.11"}), "vat_rate": forms.NumberInput(attrs={"class": "form-control", "min": "0", "step": "0.01", "placeholder": "ex: 21.00"}), } def __init__(self, *args, **kwargs): warehouse = kwargs.pop("warehouse", None) super().__init__(*args, **kwargs) if warehouse: self.fields["location"].queryset = WarehouseLocation.objects.filter( warehouse=warehouse ) if not self.instance.pk: default_loc = WarehouseLocation.objects.filter( warehouse=warehouse, is_default=True ).first() if default_loc: self.initial.setdefault("location", default_loc.pk) self.fields["num_articles"].required = False self.fields["quantity_per_article"].required = False self.fields["quantity"].required = False self.fields["unit_price"].required = False self.fields["vat_rate"].required = False if not self.instance.pk: self.fields["quantity_per_article"].initial = 1 self.fields["vat_rate"].initial = 21.00 if self.instance and self.instance.pk and self.instance.product: self.fields["product"].queryset = Product.objects.filter( Q(is_active=True) | Q(pk=self.instance.product.pk) ).order_by("name") else: self.fields["product"].queryset = Product.objects.filter(is_active=True).order_by("name") def clean(self): cleaned_data = super().clean() num_articles = cleaned_data.get("num_articles") quantity_per_article = cleaned_data.get("quantity_per_article") quantity = cleaned_data.get("quantity") if num_articles and quantity_per_article: from decimal import Decimal cleaned_data["quantity"] = int(num_articles * quantity_per_article) elif not quantity: raise forms.ValidationError( "Indiquez soit une quantité totale, soit un nombre d'articles et une quantité par article." ) # Validation des emplacements autorisés pour ce produit product = cleaned_data.get("product") location = cleaned_data.get("location") if product and location: if product.authorized_locations.exists() and location not in product.authorized_locations.all(): from django.utils.translation import gettext_lazy as _ self.add_error('location', _("L'emplacement '%(loc)s' n'est pas autorisé pour le produit '%(prod)s'.") % { 'loc': location.name, 'prod': product.name }) return cleaned_data PurchaseOrderItemFormSet = inlineformset_factory( PurchaseOrder, PurchaseOrderItem, form=PurchaseOrderItemForm, extra=1, can_delete=True, ) class InventoryForm(forms.ModelForm): class Meta: model = Inventory fields = ["warehouse_location", "performed_by", "status"] def __init__(self, *args, **kwargs): warehouse = kwargs.pop("warehouse", None) super().__init__(*args, **kwargs) if warehouse: self.fields["warehouse_location"].queryset = WarehouseLocation.objects.filter( warehouse=warehouse ).order_by("name") if not self.instance.pk: default_loc = WarehouseLocation.objects.filter( warehouse=warehouse, is_default=True ).first() if default_loc: self.initial.setdefault("warehouse_location", default_loc.pk) class InventoryItemForm(forms.ModelForm): class Meta: model = InventoryItem fields = ["product", "expected_quantity", "counted_quantity", "comment"] widgets = { "comment": forms.Textarea(attrs={"rows": 1, "placeholder": "Commentaire optionnel…"}), } def __init__(self, *args, **kwargs): kwargs.pop("warehouse", None) super().__init__(*args, **kwargs) if self.instance and self.instance.pk and self.instance.product: self.fields["product"].queryset = Product.objects.filter( Q(is_active=True) | Q(pk=self.instance.product.pk) ).order_by("name") else: self.fields["product"].queryset = Product.objects.filter(is_active=True).order_by("name") InventoryItemFormSet = inlineformset_factory( Inventory, InventoryItem, form=InventoryItemForm, extra=1, can_delete=True, ) class InventoryItemEditForm(forms.ModelForm): """Formulaire pour l'édition d'un article d'inventaire existant. Le champ produit est rendu en HiddenInput pour les articles existants, évitant de charger un