Добавлены формы для работы с документами списания

- WriteOffDocumentForm - создание/редактирование документа списания
- WriteOffDocumentItemForm - добавление/редактирование позиций документа
- Автоматическая установка текущей даты и склада по умолчанию
- Фильтрация товаров по наличию на выбранном складе
- Валидация количества с проверкой доступных остатков
- Учет текущего резерва при редактировании позиций
This commit is contained in:
2025-12-10 23:35:04 +03:00
parent 4c74ae5c73
commit 711b35488f

View File

@@ -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