Рассмотрим частую задачу, с которой сталкиваются разработчики при доработке нетиповых конфигураций (так называемых «самописок»). Представим ситуацию: на складе числится товар «Стакан». Было два поступления: первое — 10 штук по цене 100 рублей, второе — 15 штук по цене 150 рублей. Пользователь создает документ внутреннего перемещения на другой склад и указывает общее количество — 20 штук. Требуется, чтобы сразу после ввода количества программа автоматически добавила в табличную часть две строки: 10 штук по 100 рублей и 10 штук по 150 рублей. Выясним причину возникновения такой задачи, проанализируем возможные подводные камни и разберем по шагам правильные способы реализации.
Желание пользователя видеть разбиение товара по партиям и ценам прямо в интерфейсе документа — это классический архитектурный антипаттерн в парадигме 1С. Разберем подробнее, почему реализация «хотелки» прямо на форме считается плохой практикой.
В современных типовых конфигурациях табличная часть документа предназначена для отражения сути хозяйственной операции. То есть документ должен фиксировать факт перемещения физических объектов (20 стаканов), а не структуру их себестоимости. Распределение по ценам и партиям должно происходить «под капотом» в процессе проведения документа.
Проанализируем проблемы, которые возникнут при дроблении строк в интерфейсе:
Посмотрим на то, как эта задача решается методологически верно. Если предприятию действительно необходимо оценивать стоимость перемещаемых товаров по методу ФИФО (First In, First Out — «первый пришел, первый ушел»), следует перенести логику на уровень базы данных (в серверные модули обработки проведения).
Для этого в конфигурации должен вестись партионный учет. Разберем шаги его настройки в самописной базе:
Партия. Его тип обычно составной или ссылается на конкретный документ, например ДокументСсылка.ПоступлениеТоваров.ПеремещениеТоваров в процедуре ОбработкаПроведения пишется запрос к виртуальной таблице остатков регистра.Партия.Дата по возрастанию.Пользователь сможет увидеть итоговые суммы и партии, по которым произошло списание, сформировав отчет «Движения документа» или оборотную ведомость, а не в самой форме документа.
Если бизнес-требование не подлежит обсуждению, и заказчик готов оплачивать создание такого интерфейса, разработчик может реализовать механизм прямо на форме. Рассмотрим примерный серверный алгоритм, который вызывается из события ПриИзменении поля количества в табличной части.
Посмотрим на пример кода запроса, который потребуется для получения партий:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ОстаткиТоваровОстатки.Партия КАК Партия,
| ОстаткиТоваровОстатки.КоличествоОстаток КАК Количество,
| ОстаткиТоваровОстатки.СуммаОстаток / ОстаткиТоваровОстатки.КоличествоОстаток КАК Цена
|ИЗ
| РегистрНакопления.ОстаткиТоваров.Остатки(&МоментВремени, Номенклатура = &Номенклатура И Склад = &Склад) КАК ОстаткиТоваровОстатки
|УПОРЯДОЧИТЬ ПО
| ОстаткиТоваровОстатки.Партия.Дата ВОЗРАСТАНИЕ";
Запрос.УстановитьПараметр("Номенклатура", ТекущаяСтрока.Номенклатура);
Запрос.УстановитьПараметр("Склад", СкладОтправитель);
Запрос.УстановитьПараметр("МоментВремени", ТекущаяДата()); // или момент времени документа
РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();
ОсталосьСписать = ТекущаяСтрока.Количество;
ПерваяСтрокаОбработана = Ложь;
Пока Выборка.Следующий() И ОсталосьСписать > 0 Цикл
КоличествоИзПартии = Мин(ОсталосьСписать, Выборка.Количество);
Если Не ПерваяСтрокаОбработана Тогда
ТекущаяСтрока.Количество = КоличествоИзПартии;
ТекущаяСтрока.Цена = Выборка.Цена;
ПерваяСтрокаОбработана = Истина;
Иначе
НоваяСтрока = Объект.Товары.Добавить();
ЗаполнитьЗначенияСвойств(НоваяСтрока, ТекущаяСтрока);
НоваяСтрока.Количество = КоличествоИзПартии;
НоваяСтрока.Цена = Выборка.Цена;
КонецЕсли;
ОсталосьСписать = ОсталосьСписать - КоличествоИзПартии;
КонецЦикла;
Данный код демонстрирует принцип нарастающего итога: от требуемого количества отнимается доступный остаток первой партии, а остаток потребности переносится на следующую итерацию цикла, создавая новые строки.
Часто такие требования пользователей связаны с непониманием возможностей системы. Рассмотрим альтернативные пути, которые могут решить задачу без изменения логики формы:
СерииНоменклатуры. В этом случае товар физически учитывается как разные учетные единицы. Пользователь будет сам явно указывать в документе нужную серию при подборе товара со склада.Подводя итог, можно сказать: прежде чем писать сложный код обработки табличных частей на клиенте, выясните истинную причину желания пользователя. В большинстве случаев перевод учета в рамки стандартной методологии (скрытое ФИФО при проведении или использование серий) избавит вас от множества проблем с производительностью и логикой конфигурации.