Есть идеи, как реализовать создание/хранение приходной/расходной накладной на Django?

Пишу приложение (Django+MySQL) для управления складом.
Основная задача приложения - управление товарной номенклатурой и взаиморасчетами с контрагентами. Важен момент оприходования и отпуска товаров с формированием накладных + с возможностью их последующего просмотра и редактирования (по аналогии в 1C).

Я в тупике, не могу решить два вопроса:
  • как реализовать добавление и хранение "типовой накладной"
  • как реализовать форму добавления товаров в накладную (количество товаров в накладной может варьировать)


P.S. строго не судите, с Python3 работаю чуть больше года (использовал в основном для администрирования сетевых железяк и linux), писал в основном интерактивные консольные утилиты, БД MySQL обслуживал, Django - учусь по djangobook чуть больше месяца
  • Вопрос задан
  • 1316 просмотров
Решения вопроса 1
neatsoft
@neatsoft
Life is too short for bad software
В одной таблице должны храниться документы, во второй - строки табличной части (всех документов).

models.py:
from django.db import models
from django.db.models import Max, Sum
from django.utils.translation import ugettext_lazy as _


class Product(models.Model):
    name = models.CharField(
        _('Name'),
        max_length=200,
        db_index=True,
    )

    def __str__(self):
        return self.name


class Document(models.Model):
    INVOICE = 'I'
    WAYBILL = 'W'
    TYPE_CHOICES = (
        (INVOICE, _('Invoice')),
        (WAYBILL, _('Waybill')),
    )
    type = models.CharField(
        _('Type'),
        max_length=1,
        choices=TYPE_CHOICES,
    )
    number = models.CharField(
        _('Number'),
        blank=True,
        max_length=50,
    )
    created_at = models.DateTimeField(
        _('Created'),
        auto_now_add=True,
        db_index=True,
    )

    @property
    def total(self):
        return self.items.aggregate(sum=Sum('total'))['sum']

    class Meta:
        ordering = ['-created_at']


class DocumentItem(models.Model):
    document = models.ForeignKey(
        Document,
        models.CASCADE,
        related_name='items',
    )
    position = models.PositiveIntegerField(
        verbose_name=_('Position'),
        editable=False,
        db_index=True,
    )
    product = models.ForeignKey(
        Product,
        models.PROTECT,
    )
    price = models.DecimalField(
        _('Price'),
        max_digits=12,
        decimal_places=2,
    )
    quantity = models.DecimalField(
        _('Quantity'),
        max_digits=10,
        decimal_places=3,
    )
    total = models.DecimalField(
        _('Total'),
        max_digits=12,
        decimal_places=2,
    )

    def save(self, *args, **kwargs):
        if not self.position:
            position = self.document.items.aggregate(Max('position'))['position__max'] or 0
            self.position = position + 1
        super(DocumentItem, self).save(*args, **kwargs)


admin.py:
from django.contrib import admin

from .models import Product, Document, DocumentItem


@admin.register(Product)
class ProductAdmin(admin.ModelAdmin):
    pass


class DocumentItemInline(admin.TabularInline):
    model = DocumentItem
    fields = (
        'position',
        'product',
        'price',
        'quantity',
        'total',
    )
    readonly_fields = (
        'position',
    )
    ordering = ['position']


@admin.register(Document)
class DocumentAdmin(admin.ModelAdmin):
    inlines = [
        DocumentItemInline,
    ]
    list_display = (
        'type',
        'number',
        'created_at',
        'total',
    )
    list_filter = (
        'type',
    )
    search_fields = (
        '=number',
    )


Стандартная админка - для примера, вообще она не для этого (обычным пользователям она не должна быть доступна). Но реальные формы строятся по тому же принципу.

Код накидал прям здесь, не проверял, поэтому возможны незначительные ошибки.
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
Exploding
@Exploding
wtf?
Я не совсем понял, акцент на том, как организовать хранения данных в мускуле или что-то, что касается именно джанги?
Если первое - я бы разделил документы на типы: еще одно поле в таблице документов, которое бы определяло тип документа (enum "sale", "order", etc.). И зная тип, документа можно"на лету" формировать те же остатки по складу, не парясь о целостности данных. А в качестве уникальных идентификаторов для позиций поставки и по ним же отслеживать что продалось со склада - использовать например md5 хеш:
product_id + order_price ("плюс" тут рассматривать как канкатонацию параметров).
Другой вопрос, что будет потом через много-много времени... Т.к. такой вариант рассчета склада "на лету" рано или поздно будет увеличивать нагрузку на субд, но тут уже индивидуальный вопрос каждого. Если это не 100500 продаж в день то данная схема вполне может существовать и успешно разруливать на протяжении долгого времени. А там видно будет:)
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы