При оформлении продаж менеджерам часто необходимо видеть текущую себестоимость товаров непосредственно в документе РеализацияТоваровУслуг. Это позволяет оперативно оценивать маржинальность сделки. Однако в типовых конфигурациях, таких как 1С:Управление торговлей 11, ERP или Комплексная автоматизация, себестоимость не хранится в табличной части документа в явном виде, так как она является расчетной величиной.
Рассмотрим подробнее, как реализовать вывод этой информации в отдельную колонку, разберем программные методы получения данных и проанализируем нюансы, связанные с производительностью системы.
Самый надежный способ получить цифры, идентичные тем, что видит пользователь в стандартных отчетах (например, «Стоимостная оценка склада»), — это программное выполнение схемы компоновки данных (СКД) этого самого отчета. Разберем по шагам, как это реализовать.
Суть метода заключается в том, чтобы не переписывать сложный запрос расчета себестоимости (который в типовых конфигурациях может занимать сотни строк), а использовать уже готовую логику отчета. Мы программно инициализируем отчет, передаем в него нужные параметры (дата, склад, номенклатура) и выгружаем результат в ТаблицаЗначений.
Рассмотрим пример кода, который позволяет программно получить данные из схемы компоновки:
Функция ПолучитьСебестоимостьИзОтчета(СсылкаНаОбъект) Экспорт
// Находим нужный отчет в системе
ОтчетОбъект = Отчеты.СтоимостнаяОценкаСкладаВЦенахНоменклатуры.Создать();
СхемаСКД = ОтчетОбъект.СхемаКомпоновкиДанных;
// Получаем настройки по умолчанию
Настройки = ОтчетОбъект.КомпоновщикНастроек.ПолучитьНастройки();
// Устанавливаем параметры отчета
ПараметрДата = Настройки.ПараметрыДанных.Элементы.Найти("Период");
ПараметрДата.Значение = СсылкаНаОбъект.Дата;
ПараметрДата.Использование = Истина;
// Выполняем компоновку макета
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаСКД, Настройки, , , Тип("ГенераторМакетаКомпоновкиДанныхДляКоллекцииЗначений"));
// Процессор компоновки
ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновки.Инициализировать(МакетКомпоновки);
// Выводим результат в таблицу значений
ТаблицаРезультат = Новый ТаблицаЗначений;
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВКоллекциюЗначений;
ПроцессорВывода.УстановитьОбъект(ТаблицаРезультат);
ПроцессорВывода.Вывести(ПроцессорКомпоновки);
Возврат ТаблицаРезультат;
КонецФункции
Проанализируем ситуацию: этот метод гарантирует точность данных, но он очень ресурсоемкий. Если в документе сотни строк, формирование полного отчета при каждом изменении количества будет приводить к значительным задержкам (фризам) интерфейса.
Более производительный вариант — написание прямого запроса к регистрам, в которых 1С хранит стоимостную оценку. В современных конфигурациях основным источником данных является регистр накопления СебестоимостьТоваров (или СтоимостьТоваров в зависимости от версии и настроек).
Выясним причину, почему нельзя просто взять данные из регистра ВыручкаИСебестоимостьПродаж. Этот регистр заполняется только после проведения документа. Если менеджер только создает документ, данных в этом регистре еще нет. Поэтому нам нужно обращаться к остаткам по регистру СебестоимостьТоваров.
Посмотрим на пример логики запроса:
Остатки регистра СебестоимостьТоваров.Стоимость / Количество.Важный нюанс: В 1С существует понятие «Предварительная себестоимость» и «Фактическая себестоимость». Фактическая рассчитывается только регламентной операцией «Закрытие месяца». До этого момента данные в регистрах могут быть неточными или отсутствовать (если используется партионный учет 2.2 и расчет не выполнялся).
Если заказчику не принципиальна точность до копейки с учетом всех доп. расходов, а достаточно видеть «базовую» себестоимость, можно использовать механизм типов цен. Для этого создается вид цены «Себестоимость» с правилом расчета «На основании цены закупки» или «По средней за прошлый месяц».
В этом случае задача программиста упрощается до получения цен из регистра сведений ЦеныНоменклатуры:
ПараметрыЗапроса = Новый Структура;
ПараметрыЗапроса.Вставить("ВидЦены", Справочники.ВидыЦен.НайтиПоНаименованию("Себестоимость"));
ПараметрыЗапроса.Вставить("Дата", Объект.Дата);
ПараметрыЗапроса.Вставить("Номенклатура", ТекущаяСтрока.Номенклатура);
ЦенаСебестоимости = ЦенообразованиеВызовСервера.ПолучитьЦеныНоменклатуры(ПараметрыЗапроса);
Плюсы: высокая скорость работы, не нагружает систему сложными расчетами.
Минусы: это справочное значение, которое не учитывает остатки конкретных партий на складе.
Рассмотрим ситуацию с услугами, упомянутую в обсуждении. В классическом понимании 1С Услуга не имеет складской себестоимости, так как она не хранится на складе и не имеет материального воплощения. Для услуг в 1С:УТ себестоимость чаще всего равна нулю.
Однако, если ваша номенклатура имеет тип Работа, то ситуация меняется. Работы в 1С:ERP и КА могут накапливать затраты, иметь количественный учет и, соответственно, себестоимость. Если в вашем документе присутствуют именно работы, к ним применимы те же методы получения данных через регистры стоимости, что и для товаров.
Как справедливо замечено в обсуждении, расчет себестоимости «на лету» при каждом добавлении строки может превратить работу пользователя в мучение. Проанализируем способы оптимизации:
Для реализации задачи мы рекомендуем комбинированный подход. Если требуется максимальная точность — используйте программный вызов СКД отчета Стоимостная оценка склада, но делайте это по кнопке или при записи документа. Если нужна скорость и ориентировочные данные — используйте получение данных из регистра ЦеныНоменклатуры по специально выделенному типу цен.
Помните, что вывод себестоимости в Реализации товаров и услуг — это всегда компромисс между актуальностью данных и производительностью базы данных.