⟵ сюдатуда ⟶
  • Мастерклассы
  • Внешние подключения
  • Tableau и PowerBI
  • amoCRM
  • Битрикс 24
  • База знаний
  • Обращение к данным временной таблицы
  • Потеря связи с БД при большом трафике данных
  • Сохранить файл в поле по внешней ссылке url
  • Формирование списка из отмеченных галочками строк и вывод на печать
  • Добавление цикла в таблицу циклов кнопкой из временной таблицы
  • Функция TryCatch и передача данных после отката
  • Ошибка доступа при переходе в цикл если первая таблица недоступна для пользователя
  • Архитектура системы рассчитывающей остатки по кассе или складу
  • Сортировка при выборке по отображению поля Селект, а не по его основанию
  • Блокировка введения дублированного значения
  • Табличное отображение в контекстной панели
  • Сортировка строк в таблице с помощью кнопки
  • Как получить значение по условию из списка вложенных массивов?
  • Сбросить счётчик id в таблице
  • Скрытие поля в таблице по условию
  • Подтверждение действия при нажатии на кнопку в контекстном окне
  • Пересчет большой таблицы
  • Как суммировать значения в rowList по одному из ключей (по одной из колонок)
  • Наборы полей по условию при открытии через linkToTable
  • Как отложить выполнение действия и выполнить его в фоне
  • Создание и удаление строк при выборе значений в Селект или Селект-дерево
  • selectRowListForSelect с условием при котором текущее значение получается зачеркнутым
  • Не все внешние запросы на Remotes выполняются и ломается счетчик id
  • Сортировка Расчётных таблиц в Цикле
  • Как передать данные в виде чисел при обращении POST к API стороннего сервиса (must be a "integer")
  • Как сделать график если есть несколько параметров
  • Сохранение изначальных значений в поле в случае, когда поле рассчитывается кодом
  • Архитектура системы рассчитывающей остатки по кассе или складу

    Оригинал на GitHub

    Ссылка на GitHub ⟹

    Вопрос

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

    Как правильнее это реализовать с точки зрения скорости и т.п.?

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

    Как правильнее это реализовать, какие подводные камни могут быть в обоих вариантах?

    Ответ

    Проблема расчета в том, что нам надо взять список операций и его просуммировать. Если у нас будет 100 млн строк — это будет очень долго.

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

    Наиболее частый вариант в Totum — расчет в момент операции

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

    Код в поле balance c использованием параметра Исполнять только при добавлении:

    =: #sum + $prev
    
    prev: select(table: $#ntn; field: $#nf; where: 'type' = #type; order: 'id' desc)
    

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

    Если нужно иметь сводную таблицу с остатками по каждому типу, то можно сделать ее разными способами:

    Временная таблица

    В которой мы через автозаполнение создаем строки с типами и в balance берем значение из таблицы операций из последней строки.

    Код в поле balance в таблице отчета:

    =: select(table: 'operations'; field: 'balance'; where: 'type' = #type; order: 'id' desc)
    

    Временная таблица пересчитывается при открытии и возьмет актуальные данные.

    Простая таблица

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

    Но так как простая таблица сама по себе не пересчитывает строки, то нужно пересчитывать все строки типов раз в какой-то период, или, если нужна 100% актуальность, то делать это нужно в момент добавления строки в таблицу операций.

    Код действия в поле balance в таблице operationsс триггером выполнения при добавлении:

    =: recalculate(table: 'types'; where: 'type' = #type)
    

    Аналогичным решением вместо recalculate является set значения остатка в простую таблицу с типами. В этом случае, не нужно никакого кода в таблице с типами. Код действия при добавлении в поле balance таблицы operations:

    =: set(table: 'types'; field: 'balance' = $#nfv; where: 'type' = #type)
    

    Развитием этого подхода является не считать balance в таблице операций, а изменять в таблице со списком типов. В этом случае не будет поля balance в таблице operations, а код действия при добавлении будет в поле sum:

    =: set(table: 'types'; field: 'balance' + $#nfv; where: 'type' = #type)
    

    Использование + в set позволяет делать относительные изменения.

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