Регистр накоплений

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

Теоретически, можно просто сделать свойство, которое будет складывать все приходные операции, затем вычитать все расходные, при этом все операции будут задаваться в явную. Недостаток такого подхода в том, что при добавлении новой операции нужно будет добавлять ее в формулу расчета остатка. Кроме того, тяжело будет построить форму со списком всех операций, изменяющих остаток по конкретному SKU и складу. Также будет нарушена модульность, поскольку модуль, в котором будет объявлено свойство остаток, должен зависеть от всех модулей с операциями, который на него влияют.

Для реализации эффективной расширяемости системы такой функционал лучше всего реализовывать при помощи регистров. Для этого вводится абстрактный класс SKULedger, один экземпляр которого будет отражать единичное изменение остатка по одному SKU и одному складу на определенное количество (положительное или отрицательное). Для него задаются абстрактные свойства, которые должны быть заданы при реализации класса.

Все регистры могут иметь произвольное количество и тип измерений, относительно которых они действуют. В данном примере измерениями являются SKU и Склад.

Текущий остаток и остаток на определенное время рассчитываются только исходя из свойств класса SKULedger без привязки к конкретным операциям. Этот код можно и нужно объявить в отдельном модуле. Модули с конкретными операциями будут его использовать и расширять этот класс.

Например, рассмотрим одну из таких операций Поступление на склад.

Для того, чтобы "провести" ее по регистру, нужно расширить класс SKULedger классом строки поступления на склад ReceiptDetail. Также необходимо расширить свойства регистра.

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

В этом случае, строки документа нужно "проводить" по регистру дважды. По аналогии с поступлением проведем строку по регистру как расходную операцию с отрицательным количеством.

Для того, чтобы провести его по регистру для склада куда перемещается товар, воспользуемся агрегацией объектов. Строка документа перемещения будет генерировать объект класса, который в свою очередь будет "проводиться" по регистру.

Объект регистра будет создаваться только в том случае, когда документ перемещения проведен. Соответственно, в таком случае свойство posted в таком случае будет всегда равно TRUE.

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

Регистр сведений

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

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

На выходе получаем свойства, которые определяет цену по SKU и складу на дату/время, последнюю цену, а также последнюю цену по SKU для всех складов.

Аналогично регистру накоплений проводим документы по регистру сведений.

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