Как автоматически разбить строки документа по партиям и ценам (ФИФО) при вводе количества в 1С?

Программист 1С v8.3 (Управляемые формы) Управленческий учет Торговля и дистрибуция
← На главную

Рассмотрим частую задачу, с которой сталкиваются разработчики при доработке нетиповых конфигураций (так называемых «самописок»). Представим ситуацию: на складе числится товар «Стакан». Было два поступления: первое — 10 штук по цене 100 рублей, второе — 15 штук по цене 150 рублей. Пользователь создает документ внутреннего перемещения на другой склад и указывает общее количество — 20 штук. Требуется, чтобы сразу после ввода количества программа автоматически добавила в табличную часть две строки: 10 штук по 100 рублей и 10 штук по 150 рублей. Выясним причину возникновения такой задачи, проанализируем возможные подводные камни и разберем по шагам правильные способы реализации.

Архитектурный антипаттерн: почему не стоит разбивать строки на форме

Желание пользователя видеть разбиение товара по партиям и ценам прямо в интерфейсе документа — это классический архитектурный антипаттерн в парадигме 1С. Разберем подробнее, почему реализация «хотелки» прямо на форме считается плохой практикой.

В современных типовых конфигурациях табличная часть документа предназначена для отражения сути хозяйственной операции. То есть документ должен фиксировать факт перемещения физических объектов (20 стаканов), а не структуру их себестоимости. Распределение по ценам и партиям должно происходить «под капотом» в процессе проведения документа.

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

  1. Сложность редактирования. Если пользователь решит изменить количество с 20 на 18 стаканов, программе придется удалять старые строки, заново вычислять остатки, «склеивать» их и разбивать заново. Это делает логику формы тяжелой и непредсказуемой.
  2. Ошибки в многопользовательской среде. В момент работы с документом остатки актуальны на текущую секунду. Однако кладовщик может собирать накладную час. За это время другой пользователь может провести реализацию и списать первую партию. В результате при нажатии кнопки «Провести» данные на форме уже не будут соответствовать реальным остаткам в регистрах.
  3. Подмена понятий. Цена в документе внутреннего перемещения часто не несет практического смысла (так как право собственности не переходит). Себестоимость обычно учитывается в специализированных регистрах накопления.

Как правильно организовать партионный учет (ФИФО)

Посмотрим на то, как эта задача решается методологически верно. Если предприятию действительно необходимо оценивать стоимость перемещаемых товаров по методу ФИФО (First In, First Out — «первый пришел, первый ушел»), следует перенести логику на уровень базы данных (в серверные модули обработки проведения).

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

  1. В регистр остатков товаров добавляется новое измерение Партия. Его тип обычно составной или ссылается на конкретный документ, например ДокументСсылка.ПоступлениеТоваров.
  2. Остатки на регистрах теперь хранятся в разрезах: Склад, Номенклатура, Партия.
  3. В модуле объекта документа ПеремещениеТоваров в процедуре ОбработкаПроведения пишется запрос к виртуальной таблице остатков регистра.
  4. Результат запроса обязательно сортируется по полю Партия.Дата по возрастанию.
  5. В цикле программа списывает нужное количество, последовательно «откусывая» остатки от самых старых партий к самым новым, и формирует движения (записи в регистр).

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

Техническая реализация алгоритма разбиения на форме (если это критично)

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

Посмотрим на пример кода запроса, который потребуется для получения партий:


Запрос = Новый Запрос;
Запрос.Текст = 
"ВЫБРАТЬ
|   ОстаткиТоваровОстатки.Партия КАК Партия,
|   ОстаткиТоваровОстатки.КоличествоОстаток КАК Количество,
|   ОстаткиТоваровОстатки.СуммаОстаток / ОстаткиТоваровОстатки.КоличествоОстаток КАК Цена
|ИЗ
|   РегистрНакопления.ОстаткиТоваров.Остатки(&МоментВремени, Номенклатура = &Номенклатура И Склад = &Склад) КАК ОстаткиТоваровОстатки
|УПОРЯДОЧИТЬ ПО
|   ОстаткиТоваровОстатки.Партия.Дата ВОЗРАСТАНИЕ";

Запрос.УстановитьПараметр("Номенклатура", ТекущаяСтрока.Номенклатура);
Запрос.УстановитьПараметр("Склад", СкладОтправитель);
Запрос.УстановитьПараметр("МоментВремени", ТекущаяДата()); // или момент времени документа

РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();

ОсталосьСписать = ТекущаяСтрока.Количество;
ПерваяСтрокаОбработана = Ложь;

Пока Выборка.Следующий() И ОсталосьСписать > 0 Цикл
    КоличествоИзПартии = Мин(ОсталосьСписать, Выборка.Количество);
    
    Если Не ПерваяСтрокаОбработана Тогда
        ТекущаяСтрока.Количество = КоличествоИзПартии;
        ТекущаяСтрока.Цена = Выборка.Цена;
        ПерваяСтрокаОбработана = Истина;
    Иначе
        НоваяСтрока = Объект.Товары.Добавить();
        ЗаполнитьЗначенияСвойств(НоваяСтрока, ТекущаяСтрока);
        НоваяСтрока.Количество = КоличествоИзПартии;
        НоваяСтрока.Цена = Выборка.Цена;
    КонецЕсли;
    
    ОсталосьСписать = ОсталосьСписать - КоличествоИзПартии;
КонецЦикла;

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

Альтернативные бизнес-решения

Часто такие требования пользователей связаны с непониманием возможностей системы. Рассмотрим альтернативные пути, которые могут решить задачу без изменения логики формы:

  1. Учет по средней стоимости. Во многих случаях для внутреннего перемещения детальный учет по партиям избыточен. Программа может вычислять среднюю стоимость всех остатков на складе (в нашем примере: (1000 руб. + 2250 руб.) / 25 шт. = 130 рублей за штуку). Списание 20 стаканов произойдет по единой расчетной цене.
  2. Использование Серий или Характеристик. Если пользователю критически важно отличать стаканы из разных партий визуально в документе (например, у них разные поставщики, сроки годности или цвета), целесообразно использовать механизм СерииНоменклатуры. В этом случае товар физически учитывается как разные учетные единицы. Пользователь будет сам явно указывать в документе нужную серию при подборе товара со склада.

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

← На главную