diff --git a/myproject/inventory/forms.py b/myproject/inventory/forms.py index 7fb826c..40b8c1e 100644 --- a/myproject/inventory/forms.py +++ b/myproject/inventory/forms.py @@ -5,7 +5,7 @@ from decimal import Decimal from .models import ( Warehouse, Incoming, Sale, WriteOff, Transfer, Reservation, Inventory, InventoryLine, StockBatch, - TransferBatch, TransferItem, Showcase + TransferBatch, TransferItem, Showcase, WriteOffDocument, WriteOffDocumentItem, Stock ) from products.models import Product @@ -443,3 +443,110 @@ class TransferBulkForm(forms.Form): return cleaned_data + +# ============================================================================ +# WRITEOFF DOCUMENT FORMS - Документы списания +# ============================================================================ + +class WriteOffDocumentForm(forms.ModelForm): + """ + Форма создания/редактирования документа списания. + """ + class Meta: + model = WriteOffDocument + fields = ['warehouse', 'date', 'notes'] + widgets = { + 'warehouse': forms.Select(attrs={'class': 'form-control'}), + 'date': forms.DateInput(attrs={'class': 'form-control', 'type': 'date'}), + 'notes': forms.Textarea(attrs={'class': 'form-control', 'rows': 3, 'placeholder': 'Примечания к документу'}), + } + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.fields['warehouse'].queryset = Warehouse.objects.filter(is_active=True) + + # Устанавливаем дату по умолчанию - сегодня + if not self.initial.get('date'): + from django.utils import timezone + self.initial['date'] = timezone.now().date() + + # Если есть склад по умолчанию - предвыбираем его + if not self.initial.get('warehouse'): + default_warehouse = Warehouse.objects.filter( + is_active=True, + is_default=True + ).first() + if default_warehouse: + self.initial['warehouse'] = default_warehouse.id + + +class WriteOffDocumentItemForm(forms.ModelForm): + """ + Форма добавления/редактирования позиции в документ списания. + """ + class Meta: + model = WriteOffDocumentItem + fields = ['product', 'quantity', 'reason', 'notes'] + widgets = { + 'product': forms.Select(attrs={'class': 'form-control'}), + 'quantity': forms.NumberInput(attrs={'class': 'form-control', 'step': '0.001', 'min': '0.001'}), + 'reason': forms.Select(attrs={'class': 'form-control'}), + 'notes': forms.Textarea(attrs={'class': 'form-control', 'rows': 2, 'placeholder': 'Примечания'}), + } + + def __init__(self, *args, document=None, **kwargs): + super().__init__(*args, **kwargs) + self.document = document + + if document: + # Фильтруем товары - только те, что есть на складе + products_with_stock = Stock.objects.filter( + warehouse=document.warehouse, + quantity_available__gt=0 + ).values_list('product_id', flat=True) + + self.fields['product'].queryset = Product.objects.filter( + id__in=products_with_stock, + status='active' + ).order_by('name') + else: + self.fields['product'].queryset = Product.objects.filter( + status='active' + ).order_by('name') + + def clean_quantity(self): + quantity = self.cleaned_data.get('quantity') + if quantity and quantity <= 0: + raise ValidationError('Количество должно быть больше нуля') + return quantity + + def clean(self): + cleaned_data = super().clean() + product = cleaned_data.get('product') + quantity = cleaned_data.get('quantity') + + if product and quantity and self.document: + stock = Stock.objects.filter( + product=product, + warehouse=self.document.warehouse + ).first() + + if not stock: + raise ValidationError({ + 'product': f'Товар "{product.name}" отсутствует на складе' + }) + + available = stock.quantity_available - stock.quantity_reserved + + # Учитываем текущий резерв при редактировании + if self.instance.pk and self.instance.reservation: + available += self.instance.reservation.quantity + + if quantity > available: + raise ValidationError({ + 'quantity': f'Недостаточно свободного товара. ' + f'Доступно: {available}, запрашивается: {quantity}' + }) + + return cleaned_data +