refactor: стандартизация моделей документов перемещения
Приведение к единому паттерну именования документов: - TransferBatch → TransferDocument - TransferItem → TransferDocumentItem - Удалена устаревшая модель Transfer (одиночные перемещения) - Удалена неиспользуемая модель StockMovement Изменения: - models.py: переименование классов, обновление related_names - admin.py: удаление регистраций Transfer/StockMovement - forms.py: обновление TransferHeaderForm - views/transfer.py: обновление всех view классов - templates: замена transfer_batch → transfer_document - urls.py: удаление путей для movements - views/__init__.py: удаление импорта StockMovementListView - views/movements.py: удален файл Миграция: 0005_refactor_transfer_models - RenameModel операции для сохранения данных - DeleteModel для Transfer и StockMovement Единый паттерн: *Document + *DocumentItem (WriteOffDocument, IncomingDocument, 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:
@@ -215,35 +215,6 @@ class WriteOff(models.Model):
|
||||
super().save(*args, **kwargs)
|
||||
|
||||
|
||||
class Transfer(models.Model):
|
||||
"""
|
||||
Перемещение товара между складами. Сохраняет партийность.
|
||||
"""
|
||||
batch = models.ForeignKey(StockBatch, on_delete=models.CASCADE,
|
||||
related_name='transfers', verbose_name="Партия")
|
||||
from_warehouse = models.ForeignKey(Warehouse, on_delete=models.CASCADE,
|
||||
related_name='transfers_from', verbose_name="Из склада")
|
||||
to_warehouse = models.ForeignKey(Warehouse, on_delete=models.CASCADE,
|
||||
related_name='transfers_to', verbose_name="На склад")
|
||||
quantity = models.DecimalField(max_digits=10, decimal_places=3, verbose_name="Количество")
|
||||
document_number = models.CharField(max_length=100, blank=True, null=True,
|
||||
verbose_name="Номер документа")
|
||||
date = models.DateTimeField(auto_now_add=True, verbose_name="Дата операции")
|
||||
new_batch = models.ForeignKey(StockBatch, on_delete=models.SET_NULL, null=True, blank=True,
|
||||
related_name='transfer_sources', verbose_name="Новая партия")
|
||||
|
||||
class Meta:
|
||||
verbose_name = "Перемещение"
|
||||
verbose_name_plural = "Перемещения"
|
||||
ordering = ['-date']
|
||||
indexes = [
|
||||
models.Index(fields=['from_warehouse', 'to_warehouse']),
|
||||
models.Index(fields=['date']),
|
||||
]
|
||||
|
||||
def __str__(self):
|
||||
return f"Перемещение {self.batch.product.name} ({self.quantity} шт): {self.from_warehouse} → {self.to_warehouse}"
|
||||
|
||||
|
||||
class Inventory(models.Model):
|
||||
"""
|
||||
@@ -731,38 +702,6 @@ class Stock(models.Model):
|
||||
self.save()
|
||||
|
||||
|
||||
class StockMovement(models.Model):
|
||||
"""
|
||||
Журнал всех складских операций (приход, списание, коррекция).
|
||||
Используется для аудита.
|
||||
"""
|
||||
REASON_CHOICES = [
|
||||
('purchase', 'Закупка'),
|
||||
('sale', 'Продажа'),
|
||||
('write_off', 'Списание'),
|
||||
('adjustment', 'Корректировка'),
|
||||
]
|
||||
|
||||
product = models.ForeignKey(Product, on_delete=models.CASCADE,
|
||||
related_name='movements', verbose_name="Товар")
|
||||
change = models.DecimalField(max_digits=10, decimal_places=3, verbose_name="Изменение")
|
||||
reason = models.CharField(max_length=20, choices=REASON_CHOICES, verbose_name="Причина")
|
||||
order = models.ForeignKey('orders.Order', on_delete=models.SET_NULL, null=True, blank=True,
|
||||
related_name='stock_movements', verbose_name="Заказ")
|
||||
created_at = models.DateTimeField(auto_now_add=True, verbose_name="Дата создания")
|
||||
|
||||
class Meta:
|
||||
verbose_name = "Движение товара"
|
||||
verbose_name_plural = "Движения товаров"
|
||||
indexes = [
|
||||
models.Index(fields=['product']),
|
||||
models.Index(fields=['created_at']),
|
||||
]
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.product.name}: {self.change} ({self.reason})"
|
||||
|
||||
|
||||
class DocumentCounter(models.Model):
|
||||
"""
|
||||
Счетчик номеров документов для различных операций.
|
||||
@@ -811,7 +750,7 @@ class DocumentCounter(models.Model):
|
||||
return obj.current_value
|
||||
|
||||
|
||||
class TransferBatch(models.Model):
|
||||
class TransferDocument(models.Model):
|
||||
"""
|
||||
Документ перемещения товара между складами.
|
||||
Один номер документа = одна операция перемещения множественных товаров.
|
||||
@@ -819,13 +758,13 @@ class TransferBatch(models.Model):
|
||||
from_warehouse = models.ForeignKey(
|
||||
Warehouse,
|
||||
on_delete=models.CASCADE,
|
||||
related_name='transfer_batches_from',
|
||||
related_name='transfer_documents_from',
|
||||
verbose_name="Склад-отгрузки"
|
||||
)
|
||||
to_warehouse = models.ForeignKey(
|
||||
Warehouse,
|
||||
on_delete=models.CASCADE,
|
||||
related_name='transfer_batches_to',
|
||||
related_name='transfer_documents_to',
|
||||
verbose_name="Склад-приемки"
|
||||
)
|
||||
document_number = models.CharField(
|
||||
@@ -866,13 +805,13 @@ class TransferBatch(models.Model):
|
||||
return f"Перемещение {self.document_number}: {total_items} товаров, {total_qty} шт ({self.from_warehouse} → {self.to_warehouse})"
|
||||
|
||||
|
||||
class TransferItem(models.Model):
|
||||
class TransferDocumentItem(models.Model):
|
||||
"""
|
||||
Строка документа перемещения (товар в перемещении).
|
||||
Связь между документом и товарами.
|
||||
"""
|
||||
transfer_batch = models.ForeignKey(
|
||||
TransferBatch,
|
||||
transfer_document = models.ForeignKey(
|
||||
TransferDocument,
|
||||
on_delete=models.CASCADE,
|
||||
related_name='items',
|
||||
verbose_name="Документ перемещения"
|
||||
@@ -880,13 +819,13 @@ class TransferItem(models.Model):
|
||||
product = models.ForeignKey(
|
||||
Product,
|
||||
on_delete=models.CASCADE,
|
||||
related_name='transfer_items',
|
||||
related_name='transfer_document_items',
|
||||
verbose_name="Товар"
|
||||
)
|
||||
batch = models.ForeignKey(
|
||||
StockBatch,
|
||||
on_delete=models.CASCADE,
|
||||
related_name='transfer_items',
|
||||
related_name='transfer_document_items',
|
||||
verbose_name="Исходная партия (FIFO)"
|
||||
)
|
||||
quantity = models.DecimalField(
|
||||
@@ -899,17 +838,17 @@ class TransferItem(models.Model):
|
||||
on_delete=models.SET_NULL,
|
||||
null=True,
|
||||
blank=True,
|
||||
related_name='transfer_items_created',
|
||||
related_name='transfer_document_items_created',
|
||||
verbose_name="Созданная партия на целевом складе"
|
||||
)
|
||||
|
||||
class Meta:
|
||||
verbose_name = "Строка перемещения"
|
||||
verbose_name_plural = "Строки перемещения"
|
||||
unique_together = [['transfer_batch', 'batch']]
|
||||
unique_together = [['transfer_document', 'batch']]
|
||||
ordering = ['id']
|
||||
indexes = [
|
||||
models.Index(fields=['transfer_batch']),
|
||||
models.Index(fields=['transfer_document']),
|
||||
models.Index(fields=['product']),
|
||||
]
|
||||
|
||||
|
||||
Reference in New Issue
Block a user