refactor: подготовка к стандартизации Transfer моделей
Текущее состояние перед рефакторингом Transfer → TransferDocument. Все изменения с последнего коммита по улучшению системы поступлений. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -100,84 +100,9 @@ class StockBatch(models.Model):
|
||||
return f"{self.product.name} на {self.warehouse.name} - Остаток: {self.quantity} шт @ {self.cost_price} за ед."
|
||||
|
||||
|
||||
class IncomingBatch(models.Model):
|
||||
"""
|
||||
Партия поступления товара (один номер документа = одна партия).
|
||||
Содержит один номер документа и может включать несколько товаров.
|
||||
"""
|
||||
RECEIPT_TYPE_CHOICES = [
|
||||
('supplier', 'Поступление от поставщика'),
|
||||
('inventory', 'Оприходование при инвентаризации'),
|
||||
('adjustment', 'Оприходование без инвентаризации'),
|
||||
]
|
||||
|
||||
warehouse = models.ForeignKey(Warehouse, on_delete=models.CASCADE,
|
||||
related_name='incoming_batches', verbose_name="Склад")
|
||||
document_number = models.CharField(max_length=100, unique=True, db_index=True,
|
||||
verbose_name="Номер документа")
|
||||
receipt_type = models.CharField(
|
||||
max_length=20,
|
||||
choices=RECEIPT_TYPE_CHOICES,
|
||||
default='supplier',
|
||||
db_index=True,
|
||||
verbose_name="Тип поступления"
|
||||
)
|
||||
supplier_name = models.CharField(max_length=200, blank=True, null=True,
|
||||
verbose_name="Наименование поставщика")
|
||||
notes = models.TextField(blank=True, null=True, verbose_name="Примечания")
|
||||
created_at = models.DateTimeField(auto_now_add=True, verbose_name="Дата создания")
|
||||
updated_at = models.DateTimeField(auto_now=True, verbose_name="Дата обновления")
|
||||
|
||||
class Meta:
|
||||
verbose_name = "Партия поступления"
|
||||
verbose_name_plural = "Партии поступлений"
|
||||
ordering = ['-created_at']
|
||||
indexes = [
|
||||
models.Index(fields=['document_number']),
|
||||
models.Index(fields=['warehouse']),
|
||||
models.Index(fields=['receipt_type']),
|
||||
models.Index(fields=['-created_at']),
|
||||
]
|
||||
|
||||
def __str__(self):
|
||||
total_items = self.items.count()
|
||||
total_qty = self.items.aggregate(models.Sum('quantity'))['quantity__sum'] or 0
|
||||
return f"Партия {self.document_number}: {total_items} товаров, {total_qty} шт"
|
||||
|
||||
|
||||
class Incoming(models.Model):
|
||||
"""
|
||||
Товар в партии поступления. Много товаров = одна партия (IncomingBatch).
|
||||
"""
|
||||
batch = models.ForeignKey(IncomingBatch, on_delete=models.CASCADE,
|
||||
related_name='items', verbose_name="Партия")
|
||||
product = models.ForeignKey(Product, on_delete=models.CASCADE,
|
||||
related_name='incomings', verbose_name="Товар")
|
||||
quantity = models.DecimalField(max_digits=10, decimal_places=3, verbose_name="Количество")
|
||||
cost_price = models.DecimalField(max_digits=10, decimal_places=2, verbose_name="Закупочная цена")
|
||||
notes = models.TextField(blank=True, null=True, verbose_name="Примечания")
|
||||
created_at = models.DateTimeField(auto_now_add=True, verbose_name="Дата создания")
|
||||
stock_batch = models.ForeignKey(StockBatch, on_delete=models.SET_NULL, null=True, blank=True,
|
||||
related_name='incomings', verbose_name="Складская партия")
|
||||
|
||||
class Meta:
|
||||
verbose_name = "Товар в поступлении"
|
||||
verbose_name_plural = "Товары в поступлениях"
|
||||
ordering = ['-created_at']
|
||||
indexes = [
|
||||
models.Index(fields=['batch']),
|
||||
models.Index(fields=['product']),
|
||||
models.Index(fields=['-created_at']),
|
||||
]
|
||||
unique_together = [['batch', 'product']] # Один товар максимум один раз в партии
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.product.name}: {self.quantity} шт (партия {self.batch.document_number})"
|
||||
|
||||
@property
|
||||
def can_edit(self):
|
||||
"""Можно ли редактировать приход"""
|
||||
return self.stock_batch is None
|
||||
# Модели IncomingBatch и Incoming удалены - заменены на IncomingDocument/IncomingDocumentItem
|
||||
# Теперь используется упрощенная архитектура:
|
||||
# IncomingDocument → IncomingDocumentItem → StockBatch (напрямую при проведении)
|
||||
|
||||
|
||||
class Sale(models.Model):
|
||||
@@ -1207,8 +1132,8 @@ class IncomingDocument(models.Model):
|
||||
Сценарий использования:
|
||||
1. Создается черновик (draft)
|
||||
2. В течение дня добавляются товары (IncomingDocumentItem)
|
||||
3. В конце смены документ проводится (confirmed) → создаются IncomingBatch и Incoming
|
||||
4. Сигнал автоматически создает StockBatch и обновляет Stock
|
||||
3. В конце смены документ проводится (confirmed) → создается StockBatch напрямую
|
||||
4. Stock автоматически обновляется
|
||||
"""
|
||||
STATUS_CHOICES = [
|
||||
('draft', 'Черновик'),
|
||||
@@ -1216,6 +1141,12 @@ class IncomingDocument(models.Model):
|
||||
('cancelled', 'Отменён'),
|
||||
]
|
||||
|
||||
RECEIPT_TYPE_CHOICES = [
|
||||
('supplier', 'Поступление от поставщика'),
|
||||
('inventory', 'Оприходование при инвентаризации'),
|
||||
('adjustment', 'Оприходование без инвентаризации'),
|
||||
]
|
||||
|
||||
document_number = models.CharField(
|
||||
max_length=100,
|
||||
unique=True,
|
||||
@@ -1245,7 +1176,7 @@ class IncomingDocument(models.Model):
|
||||
|
||||
receipt_type = models.CharField(
|
||||
max_length=20,
|
||||
choices=IncomingBatch.RECEIPT_TYPE_CHOICES,
|
||||
choices=RECEIPT_TYPE_CHOICES,
|
||||
default='supplier',
|
||||
db_index=True,
|
||||
verbose_name="Тип поступления"
|
||||
@@ -1355,9 +1286,8 @@ class IncomingDocumentItem(models.Model):
|
||||
- Резервирование НЕ создается (товар еще не поступил)
|
||||
|
||||
При проведении документа:
|
||||
1. Создается IncomingBatch с номером документа
|
||||
2. Создается Incoming запись для каждого товара
|
||||
3. Сигнал create_stock_batch_on_incoming автоматически создает StockBatch
|
||||
1. Для каждой позиции напрямую создается StockBatch
|
||||
2. Stock автоматически обновляется
|
||||
"""
|
||||
document = models.ForeignKey(
|
||||
IncomingDocument,
|
||||
|
||||
Reference in New Issue
Block a user