commit
This commit is contained in:
@@ -3,7 +3,10 @@ from django import forms
|
||||
from django.core.exceptions import ValidationError
|
||||
from decimal import Decimal
|
||||
|
||||
from .models import Warehouse, Incoming, Sale, WriteOff, Transfer, Reservation, Inventory, InventoryLine, StockBatch
|
||||
from .models import (
|
||||
Warehouse, Incoming, Sale, WriteOff, Transfer, Reservation, Inventory, InventoryLine, StockBatch,
|
||||
TransferBatch, TransferItem
|
||||
)
|
||||
from products.models import Product
|
||||
|
||||
|
||||
@@ -82,42 +85,6 @@ class WriteOffForm(forms.ModelForm):
|
||||
return cleaned_data
|
||||
|
||||
|
||||
class TransferForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = Transfer
|
||||
fields = ['batch', 'from_warehouse', 'to_warehouse', 'quantity', 'document_number']
|
||||
widgets = {
|
||||
'batch': forms.Select(attrs={'class': 'form-control'}),
|
||||
'from_warehouse': forms.Select(attrs={'class': 'form-control'}),
|
||||
'to_warehouse': forms.Select(attrs={'class': 'form-control'}),
|
||||
'quantity': forms.NumberInput(attrs={'class': 'form-control', 'step': '0.001'}),
|
||||
'document_number': forms.TextInput(attrs={'class': 'form-control'}),
|
||||
}
|
||||
|
||||
def clean(self):
|
||||
cleaned_data = super().clean()
|
||||
batch = cleaned_data.get('batch')
|
||||
quantity = cleaned_data.get('quantity')
|
||||
from_warehouse = cleaned_data.get('from_warehouse')
|
||||
|
||||
if batch and quantity:
|
||||
if quantity > batch.quantity:
|
||||
raise ValidationError(
|
||||
f'Невозможно перенести {quantity} шт, доступно {batch.quantity} шт'
|
||||
)
|
||||
if quantity <= 0:
|
||||
raise ValidationError('Количество должно быть больше нуля')
|
||||
|
||||
# Проверяем что складской источник совпадает с складом партии
|
||||
if from_warehouse and batch.warehouse_id != from_warehouse.id:
|
||||
raise ValidationError(
|
||||
f'Партия находится на складе "{batch.warehouse.name}", '
|
||||
f'а вы выбрали "{from_warehouse.name}"'
|
||||
)
|
||||
|
||||
return cleaned_data
|
||||
|
||||
|
||||
class ReservationForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = Reservation
|
||||
@@ -339,3 +306,103 @@ class IncomingForm(forms.Form):
|
||||
'Оставьте поле пустым для автогенерации или используйте другой формат.'
|
||||
)
|
||||
return document_number
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# TRANSFER FORMS - Перемещение товаров между складами
|
||||
# ============================================================================
|
||||
|
||||
class TransferHeaderForm(forms.ModelForm):
|
||||
"""
|
||||
Форма заголовка документа перемещения товара между складами.
|
||||
Содержит информацию о складах-источнике и складе-назначении, примечания.
|
||||
"""
|
||||
class Meta:
|
||||
model = TransferBatch
|
||||
fields = ['from_warehouse', 'to_warehouse', 'notes']
|
||||
widgets = {
|
||||
'from_warehouse': forms.Select(attrs={'class': 'form-control'}),
|
||||
'to_warehouse': forms.Select(attrs={'class': 'form-control'}),
|
||||
'notes': forms.Textarea(attrs={'class': 'form-control', 'rows': 3, 'placeholder': 'Примечания к перемещению'}),
|
||||
}
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
# Фильтруем только активные склады
|
||||
self.fields['from_warehouse'].queryset = Warehouse.objects.filter(is_active=True)
|
||||
self.fields['to_warehouse'].queryset = Warehouse.objects.filter(is_active=True)
|
||||
|
||||
def clean(self):
|
||||
cleaned_data = super().clean()
|
||||
from_warehouse = cleaned_data.get('from_warehouse')
|
||||
to_warehouse = cleaned_data.get('to_warehouse')
|
||||
|
||||
if from_warehouse and to_warehouse:
|
||||
if from_warehouse.id == to_warehouse.id:
|
||||
raise ValidationError('Склад-источник и склад-назначение должны быть разными')
|
||||
|
||||
return cleaned_data
|
||||
|
||||
|
||||
class TransferLineForm(forms.Form):
|
||||
"""
|
||||
Форма для одной строки товара при массовом перемещении.
|
||||
Используется в динамической таблице для ввода нескольких товаров.
|
||||
"""
|
||||
product = forms.ModelChoiceField(
|
||||
queryset=Product.objects.filter(is_active=True).order_by('name'),
|
||||
widget=forms.Select(attrs={'class': 'form-control'}),
|
||||
label="Товар",
|
||||
required=True
|
||||
)
|
||||
|
||||
quantity = forms.DecimalField(
|
||||
max_digits=10,
|
||||
decimal_places=3,
|
||||
widget=forms.NumberInput(attrs={'class': 'form-control', 'step': '0.001'}),
|
||||
label="Количество",
|
||||
required=True
|
||||
)
|
||||
|
||||
def clean_quantity(self):
|
||||
quantity = self.cleaned_data.get('quantity')
|
||||
if quantity and quantity <= 0:
|
||||
raise ValidationError('Количество должно быть больше нуля')
|
||||
return quantity
|
||||
|
||||
|
||||
class TransferBulkForm(forms.Form):
|
||||
"""
|
||||
Комбинированная форма для ввода перемещения товаров.
|
||||
Содержит header информацию (склад-источник, склад-назначение, примечания) + динамический набор товаров.
|
||||
"""
|
||||
from_warehouse = forms.ModelChoiceField(
|
||||
queryset=Warehouse.objects.filter(is_active=True),
|
||||
widget=forms.Select(attrs={'class': 'form-control'}),
|
||||
label="Склад-отгрузки",
|
||||
required=True
|
||||
)
|
||||
|
||||
to_warehouse = forms.ModelChoiceField(
|
||||
queryset=Warehouse.objects.filter(is_active=True),
|
||||
widget=forms.Select(attrs={'class': 'form-control'}),
|
||||
label="Склад-приемки",
|
||||
required=True
|
||||
)
|
||||
|
||||
notes = forms.CharField(
|
||||
widget=forms.Textarea(attrs={'class': 'form-control', 'rows': 3, 'placeholder': 'Примечания к перемещению'}),
|
||||
label="Примечания",
|
||||
required=False
|
||||
)
|
||||
|
||||
def clean(self):
|
||||
cleaned_data = super().clean()
|
||||
from_warehouse = cleaned_data.get('from_warehouse')
|
||||
to_warehouse = cleaned_data.get('to_warehouse')
|
||||
|
||||
if from_warehouse and to_warehouse:
|
||||
if from_warehouse.id == to_warehouse.id:
|
||||
raise ValidationError('Склад-источник и склад-назначение должны быть разными')
|
||||
|
||||
return cleaned_data
|
||||
|
||||
Reference in New Issue
Block a user