Как реализовать автоматический расчет стоимости услуги на основе себестоимости материалов в 1С?

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

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

Анализ архитектуры: Справочники или Регистры?

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

  1. Отсутствие истории: Если вы измените себестоимость в справочнике сегодня, вы не сможете узнать, какой она была вчера.
  2. Сложность обновления: При изменении цены материала вам придется вручную пересчитывать стоимость всех связанных услуг.
  3. Нарушение принципов учета: Справочники предназначены для хранения условно-постоянной информации, а цены и остатки — это динамические данные.

Для решения подобных задач в 1С рекомендуется использовать Регистры сведений (например, периодический регистр «ЦеныНоменклатуры») и Документы для фиксации изменений. Тем не менее, для курсового проекта или простой учебной базы мы рассмотрим вариант реализации через прямую связь справочников.

Вариант 1. Реализация через связь справочников «Один к одному»

Рассмотрим ситуацию, когда одна услуга жестко привязана к одному основному материалу. В этом случае нам необходимо создать связь между объектами. Разберем по шагам, как это настроить в конфигураторе:

  1. Откроем справочник Услуги.
  2. На вкладке «Данные» создадим новый реквизит ОсновнойМатериал с типом СправочникСсылка.Материалы.
  3. В этом же справочнике создадим реквизит Стоимость с типом Число (точность 2, длина 15).
  4. Убедимся, что в справочнике Материалы есть реквизит Себестоимость (тип Число).

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

Разбор типичных ошибок в коде

Часто начинающие программисты пытаются использовать конструкции вида Элементы.Материалы.ТекущиеДанные в модуле объекта или обращаться к данным формы напрямую с сервера. Проанализируем ошибочный код из сообщения форума:


&НаКлиенте
Процедура МатериалыСебестоимостьПриИзменении(Элемент)
    СтрокаТабличнойЧасти = Элементы.Материалы.ТекущиеДанные;
    ИсходныеДанные = СтрокаТабличнойЧасти.Себестоимость;
    РасчетСтоимости (ИсходныеДанные);
КонецПроцедуры

Почему это не работает:

Правильный алгоритм расчета на управляемых формах

Выясним, как сделать расчет правильно. Нам нужно использовать событие ПриИзменении для поля выбора материала на форме услуги. Мы вызовем серверную процедуру, которая «сходит» в базу данных, возьмет себестоимость и вернет результат.

Рассмотрим пример кода в модуле формы справочника Услуги:


&НаКлиенте
Процедура ОсновнойМатериалПриИзменении(Элемент)
    // Вызываем серверную функцию для получения цены
    Объект.Стоимость = РассчитатьСтоимостьНаСервере(Объект.ОсновнойМатериал);
КонецПроцедуры

&НаСервереБезКонтекста
Функция РассчитатьСтоимостьНаСервере(ВыбранныйМатериал)
    // Проверяем, заполнена ли ссылка на материал
    Если ВыбранныйМатериал.Пустая() Тогда
        Возврат 0;
    КонецЕсли;
    
    // Получаем значение себестоимости напрямую из базы данных через точку
    // В 1С это допустимо, если нам нужно только одно значение
    СебестоимостьМатериала = ВыбранныйМатериал.Себестоимость;
    
    // Выполняем расчет
    Результат = СебестоимостьМатериала * 2;
    
    Возврат Результат;
КонецФункции

В данном примере мы используем директиву &НаСервереБезКонтекста для повышения производительности, так как нам не нужно передавать всю форму на сервер, достаточно только ссылки на материал.

Вариант 2. Профессиональный подход через документы и регистры

Если проект требует более серьезного подхода, рассмотрим архитектуру с использованием документов. Это позволит автоматически подтягивать актуальные цены в документы продажи (чеки, акты).

  1. Создание регистра: Создадим регистр сведений ЦеныУслуг. Измерение — Услуга, Ресурс — Цена.
  2. Документ «Установка цен»: Создадим документ, который при проведении будет записывать данные в этот регистр. В документе можно реализовать автоматическое заполнение: пройтись по всем услугам, найти связанные материалы и рассчитать цену.
  3. Документ «Оказание услуги»: В этом документе при выборе услуги в табличной части мы будем обращаться к регистру сведений.

Посмотрим на пример функции, которая получает цену из регистра в документе продажи:


&НаСервере
Процедура ЗаполнитьЦенуНаСервере(ТекущаяСтрокаID)
    СтрокаТЧ = Объект.Услуги.НайтиПоИдентификатору(ТекущаяСтрокаID);
    
    // Используем запрос или метод СрезПоследних для получения актуальной цены
    ПараметрыОтбора = Новый Структура("Услуга", СтрокаТЧ.Услуга);
    ДанныеЦены = РегистрыСведений.ЦеныУслуг.СрезПоследних(Объект.Дата, ПараметрыОтбора);
    
    Если ДанныеЦены.Количество() > 0 Тогда
        СтрокаТЧ.Цена = ДанныеЦены[0].Цена;
        СтрокаТЧ.Сумма = СтрокаТЧ.Цена * СтрокаТЧ.Количество;
    КонецЕсли;
КонецПроцедуры

Важные нюансы при работе с числами

Проанализируем еще один важный технический момент. При умножении себестоимости на коэффициенты (особенно если коэффициент дробный) часто возникают проблемы с округлением. В 1С для работы с деньгами всегда устанавливайте в свойствах реквизитов:

Если точность оставить равной 0, платформа будет округлять все ваши расчеты до целых чисел, что приведет к неверным результатам в учете.

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

← На главную