Унификация генерации номеров документов и оптимизация кода
- Унифицирован формат номеров документов: IN-XXXXXX (6 цифр), как WO-XXXXXX и MOVE-XXXXXX - Убрано дублирование функции _extract_number_from_document_number - Оптимизирована инициализация счетчика incoming: быстрая проверка перед полной инициализацией - Удален неиспользуемый файл utils.py (функциональность перенесена в document_generator.py) - Все функции генерации номеров используют единый подход через DocumentCounter.get_next_value()
This commit is contained in:
@@ -5,7 +5,8 @@ from decimal import Decimal
|
||||
|
||||
from .models import (
|
||||
Warehouse, Incoming, Sale, WriteOff, Transfer, Reservation, Inventory, InventoryLine, StockBatch,
|
||||
TransferBatch, TransferItem, Showcase, WriteOffDocument, WriteOffDocumentItem, Stock
|
||||
TransferBatch, TransferItem, Showcase, WriteOffDocument, WriteOffDocumentItem, Stock,
|
||||
IncomingDocument, IncomingDocumentItem
|
||||
)
|
||||
from products.models import Product
|
||||
|
||||
@@ -557,3 +558,94 @@ class WriteOffDocumentItemForm(forms.ModelForm):
|
||||
|
||||
return cleaned_data
|
||||
|
||||
|
||||
class IncomingDocumentForm(forms.ModelForm):
|
||||
"""
|
||||
Форма создания/редактирования документа поступления.
|
||||
"""
|
||||
class Meta:
|
||||
model = IncomingDocument
|
||||
fields = ['warehouse', 'date', 'receipt_type', 'supplier_name', 'notes']
|
||||
widgets = {
|
||||
'warehouse': forms.Select(attrs={'class': 'form-control'}),
|
||||
'date': forms.DateInput(attrs={'class': 'form-control', 'type': 'date'}),
|
||||
'receipt_type': forms.Select(attrs={'class': 'form-control'}),
|
||||
'supplier_name': forms.TextInput(attrs={'class': 'form-control', 'placeholder': 'Наименование поставщика'}),
|
||||
'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
|
||||
|
||||
# Устанавливаем тип поступления по умолчанию
|
||||
if not self.initial.get('receipt_type'):
|
||||
self.initial['receipt_type'] = 'supplier'
|
||||
|
||||
def clean(self):
|
||||
cleaned_data = super().clean()
|
||||
receipt_type = cleaned_data.get('receipt_type')
|
||||
supplier_name = cleaned_data.get('supplier_name')
|
||||
|
||||
# Для типа 'supplier' supplier_name обязателен
|
||||
if receipt_type == 'supplier' and not supplier_name:
|
||||
raise ValidationError({
|
||||
'supplier_name': 'Для типа "Поступление от поставщика" необходимо указать наименование поставщика'
|
||||
})
|
||||
|
||||
# Для других типов supplier_name не нужен
|
||||
if receipt_type != 'supplier' and supplier_name:
|
||||
cleaned_data['supplier_name'] = None
|
||||
|
||||
return cleaned_data
|
||||
|
||||
|
||||
class IncomingDocumentItemForm(forms.ModelForm):
|
||||
"""
|
||||
Форма добавления/редактирования позиции в документ поступления.
|
||||
"""
|
||||
class Meta:
|
||||
model = IncomingDocumentItem
|
||||
fields = ['product', 'quantity', 'cost_price', 'notes']
|
||||
widgets = {
|
||||
'product': forms.Select(attrs={'class': 'form-control'}),
|
||||
'quantity': forms.NumberInput(attrs={'class': 'form-control', 'step': '0.001', 'min': '0.001'}),
|
||||
'cost_price': forms.NumberInput(attrs={'class': 'form-control', 'step': '0.01', 'min': '0'}),
|
||||
'notes': forms.Textarea(attrs={'class': 'form-control', 'rows': 2, 'placeholder': 'Примечания'}),
|
||||
}
|
||||
|
||||
def __init__(self, *args, document=None, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.document = document
|
||||
|
||||
# Для поступлений можно выбрать любой активный товар (не нужно проверять наличие на складе)
|
||||
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_cost_price(self):
|
||||
cost_price = self.cleaned_data.get('cost_price')
|
||||
if cost_price is not None and cost_price < 0:
|
||||
raise ValidationError('Закупочная цена не может быть отрицательной')
|
||||
return cost_price
|
||||
|
||||
|
||||
Reference in New Issue
Block a user