В данной статье мы осуществим попытку проникновения в самое сердце "кровавого энтерпрайза" — в бухгалтерию. Вначале мы проведем исследование главной книги, счетов и баланса, выявим присущие им свойства и алгоритмы. Используем Python и технологию Test Driven Development. Здесь мы займемся прототипированием, поэтому вместо базы данных будем использовать базовые контейнеры: списки, словари и кортежи. Проект разрабатывается в соответствии с требованиями к проекту Empire ERP.


Условие задачи


Космос… Планета Эмпирея… Одно государство на всю планету. Население работает 2 часа в 2 недели, через 2 года на пенсию. План счетов состоит из 12 позиций. Счета 1-4 — активные, 5-8 — активно-пассивные, 9-12 — пассивные. Предприятие Horns & Hooves. Все транзакции выполняются в одном отчетном периоде, в начале периода остатки отсутствуют.


Настройка проекта


Клонируем проект с гитхаба:


git clone https://github.com/nomhoi/empire-erp.git

Разработку ведем на Python 3.7.4. Настраиваем виртуальное окружение, активируем его и устанавливаем pytest.


pip install pytest

1. Главная книга


Переходим в папку reaserch/day1/step1.


accounting.py:


DEBIT = 0
CREDIT = 1
AMOUNT = 2

class GeneralLedger(list):
    def __str__(self):
        res = '\nGeneral ledger'
        for e in self:
            res += '\n {:2} {:2} {:8.2f}'.format(e[DEBIT], e[CREDIT], e[AMOUNT])
        res += "\n----------------------"
        return res

test_accounting.py:


import pytest
from accounting import *
from decimal import *

@pytest.fixture
def ledger():
    return GeneralLedger()

@pytest.mark.parametrize('entries', [
    [(1, 12, 100.00),
     (1, 11, 100.00)]
])
def test_ledger(ledger, entries):
    for entry in entries:
        ledger.append((entry[DEBIT], entry[CREDIT], Decimal(entry[AMOUNT])))
    assert len(ledger) == 2
    assert ledger[0][DEBIT] == 1
    assert ledger[0][CREDIT] == 12
    assert ledger[0][AMOUNT] == Decimal(100.00)
    assert ledger[1][DEBIT] == 1
    assert ledger[1][CREDIT] == 11
    assert ledger[1][AMOUNT] == Decimal(100.00)
    print(ledger)

Главная книга, как видим, представлена в виде списка записей. Каждая запись оформлена в виде кортежа. Для записи проводки пока используем только номера счетов по дебету и кредиту и сумму проводки. Даты, описания и прочая информация пока не нужны, мы их добавим позже.


В тестовом файле создали фиксатор ledger и параметризованый тест test_ledger. В параметр теста entries передаем сразу весь список проводок. Для проверки выполняем в терминале команду pytest -s -v. Тест должен пройти, и мы увидим в терминале весь список транзакций сохраненных в главной книге:


General ledger
  1 12   100.00
  1 11   100.00

2. Счета


Теперь добавим в проект поддержку счетов. Переходим в папку day1/step2.


accounting.py:


class GeneralLedger(list):
    def __init__(self, accounts=None):
        self.accounts = accounts

    def append(self, entry):
        if self.accounts is not None:
            self.accounts.append_entry(entry)
        super().append(entry)

В классе GeneralLedger перегрузили метод append. При добавлении проводки в книгу добавляем ее сразу и в счета.


accounting.py:


class Account:
    def __init__(self, id, begin=Decimal(0.00)):
        self.id = id
        self.begin = begin
        self.end = begin
        self.entries = []

    def append(self, id, amount):
        self.entries.append((id, amount))
        self.end += amount

class Accounts(dict):
    def __init__(self):
        self.range = range(1, 13)
        for i in self.range:
            self[i] = Account(i)

    def append_entry(self, entry):
        self[entry[DEBIT]].append(entry[CREDIT], Decimal(entry[AMOUNT]))
        self[entry[CREDIT]].append(entry[DEBIT], Decimal(-entry[AMOUNT]))

Класс Accounts выполнен в виде словаря. В ключах номер счета, в значениях содержимое счета, т.е. экземпляр класса Account, который в свою очередь содержит поля начального и конечного сальдо и список транзакций имеющих отношение к этому счету. Заметим, что в этом списке суммы проводок по дебету и кредиту хранятся в одном поле, сумма по дебету положительна, сумма по кредиту отрицательна.


test_accounting.py:


@pytest.fixture
def accounts():
    return Accounts()

@pytest.fixture
def ledger(accounts):
    return GeneralLedger(accounts)

В тестовом файле добавили фиксатор accounts и поправили фиксатор ledger.


test_accounting.py:


@pytest.mark.parametrize('entries', [
    [(1, 12, 100.00),
     (1, 11, 100.00)]
])
def test_accounts(accounts, ledger, entries):
    for entry in entries:
        ledger.append((entry[DEBIT], entry[CREDIT], Decimal(entry[AMOUNT])))
    assert len(ledger) == 2
    assert ledger[0][DEBIT] == 1
    assert ledger[0][CREDIT] == 12
    assert ledger[0][AMOUNT] == Decimal(100.00)
    assert len(accounts) == 12
    assert accounts[1].end == Decimal(200.00)
    assert accounts[11].end == Decimal(-100.00)
    assert accounts[12].end == Decimal(-100.00)
    print(ledger)
    print(accounts)

Добавили новый тест test_accounts.


Запускаем тест и наблюдаем вывод:


General ledger
  1 12   100.00
  1 11   100.00
----------------------

Account 1
beg:     0.00     0.00
 12:   100.00     0.00
 11:   100.00     0.00
end:   200.00     0.00
----------------------
Account 11
beg:     0.00     0.00
  1:     0.00   100.00
end:     0.00   100.00
----------------------
Account 12
beg:     0.00     0.00
  1:     0.00   100.00
end:     0.00   100.00
----------------------

В классах Account и Acconts методы __str__ тоже перегружены, можно посмотреть в исходниках проекта. Суммы проводок и остатков для лучшей наглядности представлены в двух столбцах: по дебету и кредиту.


3. Счета: проверка проводок


Вспоминаем о таком правиле:


Остаток на активном счету может быть только по дебету.
Остаток на пассивном счету может быть только по кредиту.
Остаток на активно-пассивном счету может быть и по дебету и по кредиту.

То есть в экземпляре класса Account значение end (конечное сальдо) на активных счетах не может быть отрицательным, а на пассивных счетах не может быть положительным.


Переходим в папку day1/step3.


accounting.py:


class BalanceException(Exception):
    pass

Добавили исключение BalanceException.


class Account:
    ...
    def is_active(self):
        return True if self.id < 5 else False

    def is_passive(self):
        return True if self.id > 8 else False
    ...

В класс Account добавили проверку, к какому типу относится счет: к активному или пассивному.


class Accounts(dict):
    ...
    def check_balance(self, entry):
        if self[entry[CREDIT]].end - Decimal(entry[AMOUNT]) < 0 and self[entry[CREDIT]].is_active():
            raise BalanceException('BalanceException')
        if self[entry[DEBIT]].end + Decimal(entry[AMOUNT]) > 0 and self[entry[DEBIT]].is_passive():
            raise BalanceException('BalanceException')
    ...

В класс Accounts.py добавили проверку, если в результате добавления новой проводки на активном счету образуется отрицательное значение по дебету, то поднимется исключение, и то же самое, если на пассивном счету получится отрицательное значение по кредиту.


class GeneralLedger(list):
    ...
    def append(self, entry):
        if self.accounts is not None:
            self.accounts.check_balance(entry)
            self.accounts.append_entry(entry)

        super().append(entry)
    ...

В классе GeneralLedger перед добавлением проводки в счета выполняем проверку. Если поднимается исключение, то проводка не попадает ни в счета, ни в главную книгу.


test_accounting.py:


@pytest.mark.parametrize('entries, exception', [
    ([(12, 1, 100.00)], BalanceException('BalanceException')),
    ([(12, 6, 100.00)], BalanceException('BalanceException')),
    ([(12, 11, 100.00)], BalanceException('BalanceException')),

    ([(6, 2, 100.00)], BalanceException('BalanceException')),
    #([(6, 7, 100.00)], BalanceException('BalanceException')),
    #([(6, 12, 100.00)], BalanceException('BalanceException')),

    ([(1, 2, 100.00)], BalanceException('BalanceException')),
    #([(1, 6, 100.00)], BalanceException('BalanceException')),
    #([(1, 12, 100.00)], BalanceException('BalanceException')),
])
def test_accounts_balance(accounts, ledger, entries, exception):
    for entry in entries:
        try:
            ledger.append((entry[DEBIT], entry[CREDIT], Decimal(entry[AMOUNT])))
        except BalanceException as inst:
            assert isinstance(inst, type(exception))
            assert inst.args == exception.args
        else:
            pytest.fail("Expected error but found none")

    assert len(ledger) == 0
    assert len(accounts) == 12

В тестовый модуль добавили тест test_accounts_balance. В списке проводок сначала перечислили все возможные комбинации проводок и закомментировали все проводки, которые не поднимают исключение. Запускаем тест и убеждаемся, что оставшиеся 5 вариантов проводок поднимают исключение BalanceException.


4. Баланс


Переходим в папку day1/step4.


accounting.py:


class Balance(list):
    def __init__(self, accounts):
        self.accounts = accounts
        self.suma = Decimal(0.00)
        self.sump = Decimal(0.00)

    def create(self):
        self.suma = Decimal(0.00)
        self.sump = Decimal(0.00)
        for i in self.accounts.range:
            active = self.accounts[i].end if self.accounts[i].end >= 0 else Decimal(0.00)
            passive = -self.accounts[i].end if self.accounts[i].end < 0 else Decimal(0.00)
            self.append((active, passive))
            self.suma += active
            self.sump += passive

При создании баланса просто собираем остатки со всех счетов в одну таблицу.


test_accounting.py:


@pytest.fixture
def balance(accounts):
    return Balance(accounts)

Создали фиксатор balance.


@pytest.mark.parametrize('entries', [
    [
        ( 1, 12, 200.00), # increase active and passive
    ],[
        ( 1, 12, 200.00), # increase active and passive
        (12,  1, 100.00), # decrease passive and decrease active
    ],[
        ( 1, 12, 300.00), # increase active and passive
        (12,  1, 100.00), # decrease passive and decrease active
        ( 2,  1, 100.00), # increase active and decrease active
    ],[
        ( 1, 12, 300.00), # increase active and passive
        (12,  1, 100.00), # decrease passive and decrease active
        ( 2,  1, 100.00), # increase active and decrease active
        (12, 11, 100.00), # decrease passive and increase passive
    ]
])
def test_balance(accounts, ledger, balance, entries):
    for entry in entries:
        ledger.append(entry)
    balance.create()
    print(accounts)
    print(balance)

Создали тест test_balance. В списках параметров перечислили все возможные типы проводок: увеличивающие актив и пассив, уменьшающие актив и пассив, увеличивающие актив и уменьшающие актив, увеличивающие пассив и уменьшающие пассив. Оформили 4 варианта проводок, чтобы можно было пошагово посмотреть вывод. Для последнего варианта вывод видим такой:


General ledger
  1 12   300.00
 12  1   100.00
  2  1   100.00
 12 11   100.00
----------------------

Account 1
beg:     0.00     0.00
 12:   300.00     0.00
 12:     0.00   100.00
  2:     0.00   100.00
end:   100.00     0.00
----------------------
Account 2
beg:     0.00     0.00
  1:   100.00     0.00
end:   100.00     0.00
----------------------
Account 11
beg:     0.00     0.00
 12:     0.00   100.00
end:     0.00   100.00
----------------------
Account 12
beg:     0.00     0.00
  1:     0.00   300.00
  1:   100.00     0.00
 11:   100.00     0.00
end:     0.00   100.00
----------------------

Balance
 1 :   100.00     0.00
 2 :   100.00     0.00
 3 :     0.00     0.00
 4 :     0.00     0.00
 5 :     0.00     0.00
 6 :     0.00     0.00
 7 :     0.00     0.00
 8 :     0.00     0.00
 9 :     0.00     0.00
10 :     0.00     0.00
11 :     0.00   100.00
12 :     0.00   100.00
----------------------
sum:   200.00   200.00
======================

5. Сторно


Теперь проверим как выполняется сторно.


@pytest.mark.parametrize('entries', [
    [
        ( 1, 12, 100.00),
        ( 1, 12,-100.00),
    ]
])
def test_storno(accounts, ledger, balance, entries):
    for entry in entries:
        ledger.append(entry)
    balance.create()
    print(ledger)
    print(accounts)
    print(balance)

Вывод получили такой:


General ledger
  1 12   100.00
  1 12  -100.00
----------------------

Account 1
beg:     0.00     0.00
 12:   100.00     0.00
 12:     0.00   100.00
end:     0.00     0.00
----------------------
Account 12
beg:     0.00     0.00
  1:     0.00   100.00
  1:   100.00     0.00
end:     0.00     0.00
----------------------

Balance
 1 :     0.00     0.00
 2 :     0.00     0.00
 3 :     0.00     0.00
 4 :     0.00     0.00
 5 :     0.00     0.00
 6 :     0.00     0.00
 7 :     0.00     0.00
 8 :     0.00     0.00
 9 :     0.00     0.00
10 :     0.00     0.00
11 :     0.00     0.00
12 :     0.00     0.00
----------------------
sum:     0.00     0.00
======================

Вроде все верно.


А если мы используем такой набор проводок, то тест пройдет:


( 1, 12, 100.00),
(12,  1, 100.00),
( 1, 12,-100.00),

А если такой набор, поменяем последние 2 строки местами, то получим исключение:


( 1, 12, 100.00),
( 1, 12,-100.00),
(12,  1, 100.00),

Таким образом, чтобы отловить такую ошибку сторно нужно размещать сразу после исправляемой транзакции.


Заключение


В следующих статьях продолжим исследование бухгалтерского учета и будем рассматривать все аспекты разработки системы в соответствии со списком требований к Empire ERP.

Комментарии (55)


  1. apapacy
    13.10.2019 15:05

    Заметим, что в этом списке суммы проводок по дебету и кредиту хранятся в одном поле, сумма по дебету положительна, сумма по кредиту отрицательна.

    При такой структуре становится неразличимой при поселедущем анализе сторнирующая запись по дебету от записи по кредиту и наоборот. При этом нельзя будет вычислить правильно вычислить обороты по кредиту и по дебету. Т.к. сторнирующая запись будет учитываться в не своем обороте.


    В Ваше структуре есть некоторая избыточность. Достаточно таокй струткуры
    Д-т К-т Сумма
    1 11 100
    1 11 -100
    11 1 100 и т.п.
    Хотя сразу скажу что проводки могут быть более сложные. Одна проводка и несколько счетов дебета. Одна проводка и несколько счетов кредита. И, возможно, одна проводка и одновременно несколько счетов дебета и кредита. Хотя последний случай наверное очень редкий. Во всяком случае 1с версии 7,7 такие проводки не допускала.


    1. mikejum
      13.10.2019 15:25

      И, возможно, одна проводка и одновременно несколько счетов дебета и кредита. Хотя последний случай наверное очень редкий.

      Этот случай не редкий, а невозможный, т.к. в таком случае становится неясно, какой дебет относится к какому кредиту. Иначе говоря, появляется многовариантность.

      А по поводу сторно вы верно подметили.


      1. AleSamRU
        13.10.2019 15:54

        Почему же это невозможный случай? Есть такие сложные проводки, то есть проводки, отображенные учетными формулами, в которых несколько счетов дебетуются, одни — кредитуется или наоборот, один счет дебетуется, а несколько — кредитуются или несколько счетов дебетуется и несколько кредитуются (сборные проводки). При этом общая сумма по дебету и кредиту должна совпадать.


        1. mikejum
          13.10.2019 16:00

          Проводки, в которых несколько счетов дебетуется и один кредитуется либо один счет дебетуется и несколько кредитуется, есть — называются сложными. А чтобы несколько и дебетовались, и кредитовались — они называются сборными, — нет. Точнее, они существуют только теоретически, но применять их нельзя по причине нераскладываемости на простые проводки.


          1. AleSamRU
            13.10.2019 16:14

            Согласен, что сборные проводки у нас не применяются по указанным Вами причинам и в этом случае теряется непосредственная корреспонденция между счетами, что делает невозможным составление шахматной оборотной ведомости. Однако на Западе такие записи встречаются повсеместно.


            1. mikejum
              13.10.2019 16:26

              Не знаю, я не сталкивался с западной практикой. Честно говоря, сомневаюсь. Не только шахматную, но и любую другую оборотку корректно не составишь, и главную книгу тоже. Хотя чего не бывает на свете!


            1. nomhoi Автор
              13.10.2019 18:00

              Я, как раз, пробую выполнить насколько возможно обобщенную версию бухгалтерского учета, базовую версию. После этого для разных государств будут производные версии. Уже паттерн проектирования подобрал: State — Государство.


          1. somurzakov
            15.10.2019 20:16

            такие проводки используются во время проведения корректирующих проводок при трансформации из одной системы учета в другую (рсбу<->мсфо или us gaap<->ifrs) или при консолидации дочерних компаний в головную или при корректировке балансов по акту-сверки с контрагентом когда есть и дебетовые и кредитовые остатки


      1. loki82
        13.10.2019 23:00

        Не знаю что хабросайт сломал, но уже в третий раз пытаюсь написать комент.
        раньше НДС дробился на две поводки
        Кт 62 дт 41 — получили оплату за товар
        Кт 62 дт 19.3 выделили НДС.
        Дальше сложней.если розница то
        к-т 19.3 дт 41 восстановили НДС в товаре
        Кт 41 дт 50 продали.
        Или опт
        Кт 19.3 дт 68.2 НДС к уплате
        Кт 41 дт 62 продали товар.


        Сейчас почитал. Так не рекомендуют, хотя не знаю почему. Возможно связано с налоговым учётом. Он не равен бухгалтерском.


    1. nomhoi Автор
      13.10.2019 15:44

      При такой структуре становится неразличимой при поселедущем анализе сторнирующая запись по дебету от записи по кредиту и наоборот. При этом нельзя будет вычислить правильно вычислить обороты по кредиту и по дебету. Т.к. сторнирующая запись будет учитываться в не своем обороте.

      Спасибо за замечание. Я до оборотов пока не дошел. Буду разбираться с этой проблемой.


      В Ваше структуре есть некоторая избыточность. Достаточно таокй струткуры
      Д-т К-т Сумма
      1 11 100
      1 11 -100
      11 1 100 и т.п.

      В структуре класса Account?


      Хотя сразу скажу что проводки могут быть более сложные. Одна проводка и несколько счетов дебета. Одна проводка и несколько счетов кредита.

      Посмотрю этот момент.


      И, возможно, одна проводка и одновременно несколько счетов дебета и кредита. Хотя последний случай наверное очень редкий. Во всяком случае 1с версии 7,7 такие проводки не допускала.

      Возможна такая ситуация, например?


      1  200
      2  500
                 11 300
                 12 400


      1. apapacy
        13.10.2019 18:04

        У нас нет. В учебниках сложная проводка определяется как один ко многим. С точки зрения реализации если есть проводки типа один ко многим то будет та же структура что и многие ко многим. То есть если перейти к реляционным отношениям у вас будет строка таблицы проводка и с ней связаны несколько строк таблицы со счетами дебета и кредита и суммами.


        Но это такая идеальная структура. В реальной структуре нужно предусматривать проблемы с производительностью. Чтобы не нужно для вычисления остатков было делать запросы за весь период работы системы. Эти и вопросами кстати занимались в 80е теоретики советского бухучета. Могу порекомендовать интереснейшую книгу Кузьминский Теория бухгалтерского учёта. Очень многое из того времени было забыто и выброшено. Что то вошло в такие продукты как 1с


        1. nomhoi Автор
          13.10.2019 19:09

          Сложную проводку, вроде выше уже писали, можно разбить на простые. Отношение один ко многим.
          Как будет выглядеть структура базы данных, это еще мы рассмотрим. На производительность обязательно будет обращать внимание.
          Книгу посмотрю, спасибо.


          1. apapacy
            13.10.2019 19:37

            Разбить сложную на простые это примерно как разбить слово по слогам. То есть можно но это не отменяет наличие сложных проводок.


            1. nomhoi Автор
              14.10.2019 13:57

              Сложная проводка все равно в базу зайдет как несколько простых. У них будет общий идентификатор документа. Один-же документ у сложной проводки?


              1. apapacy
                14.10.2019 21:43

                С моей точки зрения в структуру изначально нужно закладывать данные без условностей. Я лет 15 назад работал на заводе где ит-директор как бы назвали сейчас решил внедрять erp собственной разработки. Его идея была гениальной. Обкатать на своих erp а дальше стать миллионером на ее распространении. Короче знаний об организации производства у него не было. Хотя он считал что раз он ходит через проходную в свой отдел то он стало быть является экспертом в автоматизации производства. Через пять минут общения по поводу того как работать с его erp он зашёл в маленький тупик но тут же нашелся что нужно ввести условную деталь. Ещё через пять минут оказалось что нужно вводить условного рабочего а потом условную операцию, условный станок, условную партию, условное изделие и т.п. Собственно по этим же причинам часто буксуют и внедрения самых именитых erp. Нет надлежащей привязки к конкретной предметной области. Самая распространенная ловушка, которая описана кстати у Питеркина ещё лет 20 назад это наличие наряду с конструкторской ещё и технологической спецификации изделия, я уже не говорю непрерывном внесении изменений как в конструкторскую так и в технологическую документацию а также разрешения на отклонения от технологической и конструкторской документации. А увы без всего этого наполнения erp будет такой себе чисто воображаемой конструкцией.


              1. apapacy
                14.10.2019 23:29

                Если отвечать конкретно на поставленный вопрос от можно больше вопросов получить чем ответов. Поэтому собственно каждое решение это компромис.
                Я бы не ста нагружать еще слово документ лишней нагрузкой а взял бы на вооружение слово хозяйственная операция (кстати в 1с старых версий так и было. Был документ и с ним могла быть связана операция а могла и не быть связана)


                Дальше возникает вопрос принципиальный нужно и хранить в базе реально двойную запись. То есть одну строку для дебета и одну строку для кредита. Многие теоретики автоматизации бухучета в 70-е годы пришли к выводу что это излишне. Поэтому достаточно хранить запись вида
                № хоз. оп. Счет дебета Счет кредита Сумма
                Например (номера счетов взяты с потолка)
                1 — 10 — 11 — 100
                1 — 10 — 12 — 20
                Это так для сложной проводки получится
                1с прежних версий хранил даже так сложные проводки
                1 — 10 — пусто — 120
                1 — пусто — 11 — 100
                1 — пусто — 12 — 20
                Как вы понимаете оба не очень красивые особенно 2-й.
                Первый вариант хотя бы обеспечивает сходимость сумм по дебету и кредиту т.к. сумма собвенно одна
                Если хранить операции в более клссическом с точки зрения реляционных баз виде
                № Счет Это дебет? Сумма
                1 — 10 — Дебет — 120
                1 — 11 — Кредит — 100
                1 — 12 — Кредит — 20
                Тоже плохо т.к для операций с одним номером должно выполнятся равенство сумм дебета и кредита, а это никак не обеспечивается на уровне данных (в отличие от предыдущего варианта)


                Чем дальше в лес тем больше компромисов.
                Нужно сразу иметь в виду что вычисление остатков на счете суммированием всех значений от начала и до конца будет операцией весьма накладной. Если таких записей миллиарды. Поэтому как правило или не заморачиваются (когда это еще будет столько записей и мы уже оплату всю получим) или же делают промежуточные итоги например на начало/конец месяца. Но тут опять все становится еще более зависимым. Нужно корректно блокировать базу на чтение/запись, учитывать возможность правок "задним числом". Короче люди на этой теме диссертации защищают. А суперкрасивого решения пока нет.


                1. nomhoi Автор
                  15.10.2019 14:59

                  Первый вариант самый подходящий.


                  Вопросы с базой данных поднимутся, когда уже поближе к работе с ней подойдем.


              1. somurzakov
                15.10.2019 20:20

                самый простой способ разбить любую сложную проводку на N простых это использовать Suspense Account из британской практики.
                Т.е. все что надо дебетовать дебетуем из suspense в котором 0 на балансе
                все счета что надо кредитовать кредитуем из того-же suspense и сальдо на suspense должно быть 0
                если сальдо не 0, тогда проводка не сбалансирована


    1. AleSamRU
      13.10.2019 16:10

      При такой структуре становится неразличимой при поселедущем анализе сторнирующая запись по дебету от записи по кредиту и наоборот. При этом нельзя будет вычислить правильно вычислить обороты по кредиту и по дебету. Т.к. сторнирующая запись будет учитываться в не своем обороте.

      Почему же? Для коррекции ошибок используется сторно. Это проводка со знаком минус. Она позволяет исправить неправильные данные. В итоге, в учете появляются две взаимоисключающие записи, у одной из которых есть минус. Проводки дублируют друг друга. Основные особенности сторно:
      — запись вносится за тот период, в котором была допущена ошибка;
      — основным признаком сторно является наличие минуса;
      — без такой записи итоговая отчетность будет некорректной;
      — корректирующая проводка делается на ту сумму, на которую была установлена разница.
      В журнале операций как раз так всё и записывается (скажем так, правильные проводки — даются «черным», а исправляющие (сторнирующие) проводки — «красным»), поэтому при его анализе как раз видно отрицательное число в обороте по счету и оно исправляет (обнуляет) как раз неправильный (получившийся с ошибкой) оборот. Есть также дополняющие проводки, но они здесь пока не рассматриваются.


    1. nomhoi Автор
      15.10.2019 16:03

      При такой структуре становится неразличимой при поселедущем анализе сторнирующая запись по дебету от записи по кредиту и наоборот. При этом нельзя будет вычислить правильно вычислить обороты по кредиту и по дебету. Т.к. сторнирующая запись будет учитываться в не своем обороте.

      Можно добавить поле в таблице для установки специального флага для таких записей, чтобы они не учитывались при составлении оборотной ведомости. Добавить Boolean поле будет дешевле, чем еще одно Decimal поле. Другой вариант: добавить в Account поля для оборотов для их подсчета сразу при добавлении записей на счет и при добавлении сторно правильным образом эти обороты обновлять.


  1. mikejum
    13.10.2019 15:23

    Остаток на активном счету может быть только по дебету.
    Остаток на пассивном счету может быть только по кредиту.
    Остаток на активно-пассивном счету может быть и по дебету и по кредиту.

    У вас причина и следствие поменяны местами.
    Если по счету возможен только дебетовый остаток, такой счет называется активным.
    И т.д.


    1. nomhoi Автор
      13.10.2019 15:47

      А, по-моему, без разницы. Существуют активные счета. Активные счета обладают определенными свойствами.


      Я с бухгалтерией раньше не имел дела. Вот только изучаю. Буду признателен за любые замечания и предложения.


      1. mikejum
        13.10.2019 15:49

        Возможность дебетового или(и) кредитового сальдо и определяет название счета.


        1. nomhoi Автор
          13.10.2019 15:57

          Хорошо, я не буду спорить, почитаю ваши книги.


          1. mikejum
            13.10.2019 16:03
            +1

            Почитайте.
            Если вы начинающий, рекомендую «Бухучет за 20 минут» и «Понимаете ли вы бухгалтерский учет?».


            1. nomhoi Автор
              13.10.2019 17:44

              Спасибо, посмотрю. Я пока смотрел такие курсы:
              http://www.finbuh1c.ru/
              https://www.accountingcoach.com/


      1. vasilyevii
        14.10.2019 13:39

        Изучите 1С бухгалтерию, можно купить ее, думаю тысяч в 10 обойдётся
        В ней бухгалтерский и налоговый учёт проработан уже проработан
        Может поймёте, что пытаетесь изобрести велосипед


        1. nomhoi Автор
          14.10.2019 13:40

          Мой велосипед круче, посмотрите список требований.


    1. puyol_dev2
      13.10.2019 21:05

      Активный счет такой, где приход средств записывается в дебет, а расход в кредит, и наоборот — в пассивный счет приход дс идет в кредит, а расход в дебет


      1. mikejum
        13.10.2019 21:19

        Наверное, экзамен у вас с таким ответом приняли бы. Но видите ли, я этими вопросами слишком долго и профессионально занимался… Из вашего ответа можно заключить: берем счет и называем его активным или пассивным. Но все совсем не так. Они уже либо активные, либо пассивные, в зависимости от того, что на них учитывается. Объекты, учитываемые на счетах — это причина того, активный счет или пассивный (соответственно, какая сторона увеличивает сумму на счете, а какая уменьшает).
        Вы уж извините, но читать лекцию на эту тему мне недосуг. Да это и долго.


        1. Viceroyalty
          14.10.2019 03:02

          А ведь порой ни какие знания не помогают — и нужно просто смотреть план счетов (если у вас, конечно, банковский бухучет, а не клиентский)


          1. apapacy
            14.10.2019 18:47

            Есть две такие интересные дисциплины: история бухучета и теория бухучета. Не думаю что они сильно помогают практическим бухгалтерам в их повседневной практике. Но для тех кто хочет получить представление о системе бухучета вцелом для разработки армов бухгалтера я бы очень рекомендовал.


            1. Viceroyalty
              14.10.2019 18:51

              Занимательно, надеюсь разработчики о них не забудут (я-то всегда пользователем general ledger был)


              1. apapacy
                14.10.2019 21:22

                Это интереснейшая область. Как возникла двойная запись и т.п. У истоков бухучета в его современном виде стояли такие учёные как Кардано из школьного учебника с формулой Кардано, Даниель Дефо тот самый со своим Робинзоном и Лука Пачоли который был а кругу общения Леонардо да Винчи.


      1. VolCh
        13.10.2019 21:25

        А активно-пассивный? :)


        1. Ndochp
          14.10.2019 11:27

          А это значит свели вместе 2 позиции. Чаще всего это групповой счет, с пассивным и активным субсчетами.


        1. apapacy
          14.10.2019 13:50

          Активно-пассивные счета возникают для отражений операций товар деньги товар. Они характеризуются разницей во времени предоплата и постоплата а также результатом прибыли или убытки. От этого и возникает вот эта двойственность. По своему смыслу эти счета очень близки к пассивным. О.кю на них не учитывается активы а источники. Например поставщик поставил нам материалы и мы отразили в активах эти материалы и тот факт что источником финансирования этих материалов является наша задолженность перед поставщиком. Или противоположный случай мы сделали предоплату маткриало и списали деньги с активов. И возникает уже долг поставщика перед нами. Поэтому остаток может быть как на дебета так и на кредите.


      1. frrrost
        14.10.2019 02:59

        Не знаю, как в МСФО, но по РСБУ довольно простое разделение: активы — это то, что можно «потрогать руками», пассивы — это обязательство (очень упрощенно: долги)
        Например, пришел товар от поставщика: одновременно увеличился активный 41 счет (пришло что-то материальное) и так же увеличился 62 счет — мы стали «должны» поставщику денег за товар. Заплатим деньги с «материального» 51 счета и наш «долг» закроется.

        Когда только начинаешь изучать бух. учет бывает очень полезно спрашивать себя «можно ли это потрогать?». Если можно — счет точно активный, ставим его в Дт или Кт в зависимости от того, плюс это или минус. Ну а корр. счету остается незанятое место в проводке


        1. frrrost
          14.10.2019 10:09

          только в примере не 62 счет, а 60, конечно же. Постоянно их путаю


        1. surly
          14.10.2019 11:06

          активы — это то, что можно «потрогать руками», пассивы — это обязательство (очень упрощенно: долги)… очень полезно спрашивать себя «можно ли это потрогать?». Если можно — счет точно активный

          Это правило помогает не всегда. Мне не помогло, например, понять счёт «Уставный капитал». Собрались учредители, внесли уставный капитал. Он формирует денежное имущество фирмы, на эти средства фирма теперь может что-нибудь закупить. Однако, в плане счетов этот счёт является пассивным. Я так и не понял, почему. Ведь, казалось бы, в результате этих взносов никаких долговых обязательств не сформировалось; материальных ценностей во владении фирмы прибыло. Почему пассивный?


          1. VolCh
            14.10.2019 11:09

            Это типа долговых обязательств перед учредителями.


            1. surly
              14.10.2019 11:17

              Вот это и непонятно. Сообразили мы на троих, скинулись по пятёрке. Всё, у конторы теперь есть 15 тыщ уставного капитала, на которые она начинает дело. Случится прибыль — поделим на троих. Не случится — ну что ж, нам не повезло, деньги мы выкинули на воздух. Какие такие долговые обязательства?


              1. Kreastr
                14.10.2019 12:39

                Как это работает в Финляндии. 15 тысяч записанные в пассивы это именно долг компании перед учредителями. Одновременно с этой записью появляется запись на 15 тысяч в активах на банковском или кассовом счету, то есть операция сбалансирована. Далее упрощенный пример в котором пропущены несколько шагов. Если компания, допустим окажет кому-то услугу на 5 тысяч, то появится еще две записи: 5 тысяч в активах на банковском счету компании и 5 тысяч в пассивах на счету нераспределенная прибыль. В конце отчетного периода компания может решить что делать с деньгами в этой категории. Если они будут выплачены в виде дивидендов, то с активов и пассивов спишут эти 5 тысяч и все вернется к начальному состоянию.

                Другая ситуация: если акционеры решат реинвестировать прибыль, то ту часть, которую они реинвестируют, в пассивах переведут со счета нераспределенной прибыли на счет «прибыль от прошлых финансовых периодов». Этот счет эквивалентен уставному капиталу и обозначает задолженность компании перед учредителями.

                Таким образом активные счета это «что у нас есть», а пассивные «кому мы это должны (себе или внешним кредиторам)». Особенно важно помнить что в активных счетах могут быть и совсем нематериальные вещи. Например, если вы оказываете услугу, то на самом деле в первую очередь возникает долг перед покупателем (пропущенный этап в объяснении выше) и только потом, после оплаты, этот долг превращается в сумму на счету в банке. То есть между оказанием услуги и оплатой существует актив «долговые обязательства».


                1. nomhoi Автор
                  14.10.2019 13:37

                  Например, если вы оказываете услугу, то на самом деле в первую очередь возникает долг перед покупателем (пропущенный этап в объяснении выше) и только потом, после оплаты, этот долг превращается в сумму на счету в банке.

                  Вроде долг перед покупателем образуется в том случае, если покупатель оплатил, а услуга еще не оказана. После оказания услуги долг исчезает.
                  Если была указана услуга до оплаты, до долг у покупателя до оплаты услуги.


                  1. Kreastr
                    14.10.2019 13:45

                    Да, вы правы. Заговорился. Конечно же это «долг покупателя», а не «долг перед покупателем».


          1. frrrost
            14.10.2019 11:18

            Тут просто надо подумать, как будет оформляться этот «уставной капитал». Никто же не говорит просто «вот, держите, моя доля в УК». Эта доля чем-то обеспечена.

            • Принес деньги — положили их в банк на 51 — в корреспонденции остался УК как «обязательство» перед учредителем за эти деньги
            • Принес компьютер — положили его в Основные средства (на самом деле нет). В корреспонденции опять УК, который явно оказывается пассивом.


            В общем, надо к проводке все сводить, тогда становится понятнее


          1. apapacy
            14.10.2019 13:20

            Если слово обязательства заменить на слово источники то все будет понятнее


  1. loki82
    13.10.2019 22:32

    Не знаю почему до сих пор пытаются понять бухгалтерию по активны, пассивным или ап счетам. Гораздо интересней взять 1с 6.0 и посмотреть на типовые проводки. Очень помогает разобраться, а что же происходит в бухгалтерии. Пример:
    Поступили деньги от покупателя кт62-дт50
    Деньги перевели в банк кт50-дт51
    Оплатили поставщику кт51-дт60
    Поставщик отгрузил товары к-т 60 — дт 41
    Отдали товар к-т 41-дт62
    Круг замкнулся
    я привёл упрощённую схему для понимания бух учёта. Но в России бух учёт не равно налоговый. И есть куча нюансов.


    1. nomhoi Автор
      14.10.2019 13:33
      +1

      Задача стоит исследовать все свойства бух-учета. Без понимания этих вещей получается не обойтись.


      1. loki82
        14.10.2019 14:28

        Я не совсем понял цель проекта. Специально зашел на Гит, еще на какой то сайт. Это разработка 1С на Python? Цель проекта, образовательная? Это как изучать андроид накидывая блоки, только в бухгалтерский учет? Или на выходе должен быть полноценный Framework? Тогда без указания, что такое операция, и что такое проводки внутри операции, только еще больше запутывают.
        Для себя определил так.
        Активный — это тот счет, на котором увеличение по дебету, уменьшение по кредиту(41,50,51).
        Пассивный — это счет, на котором увеличение по кредиту, уменьшение по дебету(60.1, 62.2).
        Активно/пассивные — это счет на которых можно и так и так(налоги 68, персонал 76).
        Но все равно лучше на примерах типовых операций. Оснобенно при сведении баланса. Там как раз активные и пассивыне счета закрываются.


        1. nomhoi Автор
          14.10.2019 15:10

          Я не совсем понял цель проекта. Специально зашел на Гит, еще на какой то сайт. Это разработка 1С на Python? Цель проекта, образовательная? Это как изучать андроид накидывая блоки, только в бухгалтерский учет? Или на выходе должен быть полноценный Framework? Тогда без указания, что такое операция, и что такое проводки внутри операции, только еще больше запутывают.
          Для себя определил так.

          Вначале статьи все уже написано.


  1. Art_VN
    14.10.2019 13:26

    Поскольку каждая проводка должна иметь документальное подтверждение то, ИМХО, проводки нужно рассматривать в разрезе хозяйственных операций. При таком подходе буху будет более понятно что происходит с системой при проведении документа.


    1. nomhoi Автор
      14.10.2019 13:30

      Я в статье написал, что даты, описания и прочая информация пока опускается для упрощения задачи. Важно было вначале понять, как формируются счета и баланс без лишней писанины.


      1. Art_VN
        15.10.2019 09:09

        А пробовали формировать баланс при наличии остатка и по дт и по кт активно-пассивного счета?


        1. nomhoi Автор
          15.10.2019 14:48

          Нет, пока по условиям задачи на начало периода остатков нет.