При проектировании конфигураций в среде «1С:Предприятие 8.3» начинающие разработчики часто совершают классические архитектурные ошибки. Одной из самых распространенных является попытка переносить данные напрямую из одного документа в другой или создавать жесткую структуру табличных частей с фиксированными колонками под каждый вид затрат. Рассмотрим, как решить задачу сопоставления плановой и фактической себестоимости продукции, используя правильные паттерны проектирования 1С.
Выясним причину, почему подход с фиксированными реквизитами табличной части («Сырье и материалы», «Комплектующие», «Заработная плата» и т.д.) нежизнеспособен. Если завтра на предприятии появится новый вид расходов, например, «Аренда оборудования» или «Логистика», вам придется полностью перестраивать структуру метаданных, переписывать код проведения документов и переделывать все отчеты. Разберем по шагам, как построить гибкую, масштабируемую и профессиональную архитектуру базы данных.
Для того чтобы система была гибкой, нам необходимо отказаться от жестких реквизитов табличных частей. Вместо этого мы применим аналитический подход с использованием субконто и справочников. Нам понадобятся два ключевых справочника:
Сырье и материалы, Топливо и энергия, Оплата труда, Общепроизводственные расходы и другие. Мы можем создать их как предопределенные элементы конфигурации или позволить пользователю вводить их вручную в режиме «1С:Предприятие».Теперь спроектируем табличную часть для документов «Плановая калькуляция» и «Фактическая калькуляция». Вместо десятка колонок под каждый вид затрат мы создадим всего одну универсальную табличную часть с именем Затраты. В ней будут следующие реквизиты:
СтатьяЗатрат (Тип: СправочникСсылка.СтатьиЗатрат) — указывает на вид расхода.Номенклатура (Тип: СправочникСсылка.Номенклатура) — детализирует конкретный материал или услугу (необязательное поле, если для некоторых статей аналитика по материалам не требуется).Сумма (Тип: Число, длина 15, точность 2, неотрицательное).Количество (Тип: Число, длина 15, точность 3, неотрицательное).Такая структура позволит нам добавлять неограниченное количество статей расходов без изменения конфигурации и написания нового кода.
Проанализируем ситуацию: нам нужно построить три отчета — плановую себестоимость, фактическую себестоимость и отклонение плана от факта. Если мы создадим отдельные регистры для плана и для факта, нам придется писать сложные запросы с полным соединением (ПОЛНОЕ СОЕДИНЕНИЕ) таблиц в СКД, обрабатывать значения NULL и бороться с потерей данных.
Чтобы избежать этих сложностей, мы применим стандартный паттерн разработки 1С — использование единого оборотного регистра накопления с измерением сценария.
Сначала создадим перечисление Сценарии со следующими значениями:
ПланФактЗатем создадим регистр накопления ЗатратыПродукции. В свойствах регистра обязательно укажем вид регистра: Обороты. Поскольку нам не нужно контролировать остатки на складах в рамках этой задачи, а интересует только накопленный объем затрат за период (месяц), оборотный регистр идеально подходит по производительности.
Настроим структуру регистра ЗатратыПродукции:
Измерения:
Продукция (Тип: СправочникСсылка.Номенклатура) — готовая продукция, на которую распределяются затраты.СтатьяЗатрат (Тип: СправочникСсылка.СтатьиЗатрат) — вид расхода.Сценарий (Тип: ПеречислениеСсылка.Сценарии) — ключевой разделитель плановых и фактических данных.Ресурсы:
Сумма (Тип: Число, длина 15, точность 2)Количество (Тип: Число, длина 15, точность 3)Теперь рассмотрим, как документы будут отражать данные в нашей системе. У нас есть два ключевых документа: ПлановаяКалькуляция и ФактическаяКалькуляция. Оба документа должны иметь в шапке реквизит Продукция (тип СправочникСсылка.Номенклатура) и табличную часть Затраты.
При проведении документа ПлановаяКалькуляция система должна записать данные в регистр накопления под сценарием План. Напишем обработчик проведения документа. Для этого можно воспользоваться «Конструктором движений» или написать код вручную:
Процедура ОбработкаПроведения(Отказ, РежимПроведения)
// Очищаем движения перед записью новых
Движения.ЗатратыПродукции.Записывать = Истина;
Движения.ЗатратыПродукции.Очистить();
Для Каждого ТекСтрокаЗатраты Из Затраты Цикл
// Создаем новую запись движения по регистру
Движение = Движения.ЗатратыПродукции.Добавить();
// Заполняем стандартные реквизиты
Движение.Период = Дата;
// Заполняем измерения регистра
Движение.Продукция = Продукция;
Движение.СтатьяЗатрат = ТекСтрокаЗатраты.СтатьяЗатрат;
Движение.Сценарий = Перечисления.Сценарии.План; // Принудительно устанавливаем План
// Заполняем ресурсы регистра
Движение.Сумма = ТекСтрокаЗатраты.Сумма;
Движение.Количество = ТекСтрокаЗатраты.Количество;
КонецЦикла;
КонецПроцедуры
Для документа ФактическаяКалькуляция код обработчика проведения будет практически идентичным, за исключением того, что в измерение Сценарий мы запишем значение Перечисления.Сценарии.Факт:
Процедура ОбработкаПроведения(Отказ, РежимПроведения)
Движения.ЗатратыПродукции.Записывать = Истина;
Движения.ЗатратыПродукции.Очистить();
Для Каждого ТекСтрокаЗатраты Из Затраты Цикл
Движение = Движения.ЗатратыПродукции.Добавить();
Движение.Период = Дата;
Движение.Продукция = Продукция;
Движение.СтатьяЗатрат = ТекСтрокаЗатраты.СтатьяЗатрат;
Движение.Сценарий = Перечисления.Сценарии.Факт; // Принудительно устанавливаем Факт
Движение.Сумма = ТекСтрокаЗатраты.Сумма;
Движение.Количество = ТекСтрокаЗатраты.Количество;
КонецЦикла;
КонецПроцедуры
Для того чтобы облегчить работу бухгалтера или экономиста, добавим в документ ФактическаяКалькуляция возможность автоматического заполнения фактических данных на основе ранее введенных плановых показателей. Для этого создадим на форме документа команду ЗаполнитьПоПлану и привяжем ее к кнопке.
Рассмотрим серверный метод, который будет выполнять запрос к нашему регистру накопления за выбранный период и по выбранной продукции, извлекая плановые показатели:
&НаСервере
Процедура ЗаполнитьПоПлануНаСервере()
// Проверим заполнение ключевого реквизита в шапке
Если Не ЗначениеЗаполнено(Объект.Продукция) Тогда
ВызватьИсключение "Не заполнена продукция в шапке документа!";
КонецЕсли;
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ЗатратыПродукцииОбороты.СтатьяЗатрат КАК СтатьяЗатрат,
| ЗатратыПродукцииОбороты.Номенклатура КАК Номенклатура,
| ЗатратыПродукцииОбороты.СуммаОборот КАК Сумма,
| ЗатратыПродукцииОбороты.КоличествоОборот КАК Количество
|ИЗ
| РегистрНакопления.ЗатратыПродукции.Обороты(&НачалоПериода, &КонецПериода, , Продукция = &Продукция И Сценарий = &СценарийПлан) КАК ЗатратыПродукцииОбороты";
// Устанавливаем границы периода в пределах месяца документа
Запрос.УстановитьПараметр("НачалоПериода", НачалоМесяца(Объект.Дата));
Запрос.УстановитьПараметр("КонецПериода", КонецМесяца(Объект.Дата));
Запрос.УстановитьПараметр("Продукция", Объект.Продукция);
Запрос.УстановитьПараметр("СценарийПлан", Перечисления.Сценарии.План);
РезультатЗапроса = Запрос.Выполнить();
Если Не РезультатЗапроса.Пустой() Тогда
Объект.Затраты.Очистить();
Выборка = РезультатЗапроса.Выбрать();
Пока Выборка.Следующий() Цикл
НоваяСтрока = Объект.Затраты.Добавить();
ЗаполнитьЗначенияСвойств(НоваяСтрока, Выборка);
КонецЦикла;
Иначе
ПоказатьПредупреждение(, "Плановые данные за указанный период не найдены.");
EndЕсли;
КонецПроцедуры
Этот простой алгоритм решает проблему ручного переноса данных. Пользователю останется лишь скорректировать суммы и объемы ресурсов под реальные факты хозяйственной жизни предприятия.
Использование единой таблицы оборотов значительно упрощает построение всех трех отчетов на Системе компоновки данных (СКД). Разберем, как спроектировать их без единой строчки кода в модулях отчетов.
Для всех отчетов источником данных будет выступать одна и та же виртуальная таблица: РегистрНакопления.ЗатратыПродукции.Обороты.
Сценарий Равно Значение(Перечисление.Сценарии.План). В выбранные поля добавляем Продукция, СтатьяЗатрат, СуммаОборот и КоличествоОборот.Сценарий Равно Значение(Перечисление.Сценарии.Факт).Продукция и СтатьяЗатрат.Сценарий.СуммаОборот (предварительно добавив его на вкладку «Ресурсы» схемы компоновки данных).При такой настройке платформа автоматической кросс-таблицей выведет в строках наши статьи затрат и продукцию, а в колонках отобразит две группы колонок — «План» и «Факт».
Чтобы рассчитать само отклонение (разницу между планом и фактом), мы перейдем на вкладку «Вычисляемые поля» нашей схемы компоновки данных и добавим новое поле:
ОтклонениеВыбор Когда Сценарий = Значение(Перечисление.Сценарии.План) Тогда СуммаОборот Иначе -СуммаОборот КонецОтклонениеЗатем перейдем на вкладку «Ресурсы» и добавим поле Отклонение с выражением расчета Сумма(Отклонение). В настройках структуры отчета выведем поле Отклонение в ресурсы таблицы. Система автоматически сгруппирует данные и выведет разницу в отдельном столбце.
Использование предложенного подхода гарантирует чистоту кода, отсутствие дублирования информации в базе данных и полное соответствие стандартам разработки фирмы «1С». Это не только упростит написание курсовой работы, но и заложит правильный фундамент для дальнейшей профессиональной деятельности.