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