Загрузка данных


Всё это можно сделать, причём так, чтобы вы настраивали прайс прямо в форме, как в типовом прайс-листе УНФ. Ниже схема работы и полный код, который заменяет предыдущий.

Что получится

Форма станет из нескольких вкладок:

Основное: вид цен, откуда брать наименование (обычное, полное/для печати или дополнительное свойство, например «Наименование для сайта»), галочки «только в наличии», «только товары (без услуг и работ)», «выводить названия групп».
Колонки: список колонок с галочками, возможностью переименовать и стрелками «Вверх/Вниз» для порядка. Есть колонки «Остаток» и «Доп. свойство 1–3». В них можно вывести любой дополнительный реквизит, например производителя.
Отбор: выбор складов (галочками) и выбор групп номенклатуры (пусто означает все).
Письмо: учётная запись, получатели, тема, текст, формат.
Предпросмотр: кнопка «Предпросмотр» показывает готовый прайс до отправки.

Всё сохраняется отдельно для каждого из 3 профилей. Форма строит свои элементы сама, поэтому перетаскивать поля мышкой не придётся.

Порядок действий
Сделайте копию текущего .epf на случай отката.
Откройте его в Конфигураторе: Файл → Открыть.
Откройте модуль объекта, удалите всё и вставьте код из блока 1.
В дереве раскройте «Формы», удалите старую форму Форма (правая кнопка → Удалить, на вопросы отвечайте «Да»). Создайте новую форму: «Формы» → Добавить, имя Форма, остальное по умолчанию. Если у обработки очистилось свойство «Основная форма», выберите там новую форму.
Откройте модуль новой формы, удалите всё и вставьте код из блока 2.
Нажмите Ctrl+F7, затем сохраните файл.
В УНФ откройте карточку обработки → «Обновить из файла…» → «Записать и закрыть».
Запустите «Настройка рассылки прайс-листов». Колонки и склады подтянутся сами. Настройте всё, нажмите «Предпросмотр», затем «Сохранить настройки».

Реквизиты самой обработки (ТипЦен, Группа и т. д.) можно оставить как есть или удалить, новый код их не использует.

Блок 1. Модуль объекта
bsl
#Область ПрограммныйИнтерфейс

Функция СведенияОВнешнейОбработке() Экспорт

	ПараметрыРегистрации = ДополнительныеОтчетыИОбработки.СведенияОВнешнейОбработке("2.2.2.1");
	ПараметрыРегистрации.Вид = ДополнительныеОтчетыИОбработкиКлиентСервер.ВидОбработкиДополнительнаяОбработка();
	ПараметрыРегистрации.Версия = "2.0";
	ПараметрыРегистрации.БезопасныйРежим = Ложь;
	ПараметрыРегистрации.Информация = "Отправка прайс-листов по e-mail по расписанию";

	Команда = ПараметрыРегистрации.Команды.Добавить();
	Команда.Представление = "Настройка рассылки прайс-листов";
	Команда.Идентификатор = "Форма";
	Команда.Использование = ДополнительныеОтчетыИОбработкиКлиентСервер.ТипКомандыОткрытиеФормы();
	Команда.ПоказыватьОповещение = Ложь;

	Для Номер = 1 По 3 Цикл
		Команда = ПараметрыРегистрации.Команды.Добавить();
		Команда.Представление = "Отправить прайс-лист (профиль " + Номер + ")";
		Команда.Идентификатор = "Прайс" + Номер;
		Команда.Использование = ДополнительныеОтчетыИОбработкиКлиентСервер.ТипКомандыВызовСерверногоМетода();
		Команда.ПоказыватьОповещение = Истина;
	КонецЦикла;

	Возврат ПараметрыРегистрации;

КонецФункции

Процедура ВыполнитьКоманду(ИдентификаторКоманды, ПараметрыВыполнения = Неопределено) Экспорт

	Номер = Число(СтрЗаменить(ИдентификаторКоманды, "Прайс", ""));
	ОтправитьПрайс(ПолучитьНастройки(Номер));

КонецПроцедуры

// Список колонок, которые умеет выводить прайс.
Функция КаталогПолей() Экспорт

	Каталог = Новый ТаблицаЗначений;
	Каталог.Колонки.Добавить("Поле");
	Каталог.Колонки.Добавить("Название");
	Каталог.Колонки.Добавить("Ширина");
	Каталог.Колонки.Добавить("ПоУмолчанию");

	ДобавитьПолеКаталога(Каталог, "Артикул", "Артикул", 15, Истина);
	ДобавитьПолеКаталога(Каталог, "Наименование", "Наименование", 55, Истина);
	ДобавитьПолеКаталога(Каталог, "Характеристика", "Характеристика", 20, Ложь);
	ДобавитьПолеКаталога(Каталог, "Единица", "Ед. изм.", 8, Истина);
	ДобавитьПолеКаталога(Каталог, "Цена", "Цена", 14, Истина);
	ДобавитьПолеКаталога(Каталог, "Остаток", "Остаток", 12, Ложь);

	// Колонка появится, только если такой реквизит есть у номенклатуры
	Если Метаданные.Справочники.Номенклатура.Реквизиты.Найти("Производитель") <> Неопределено Тогда
		ДобавитьПолеКаталога(Каталог, "Производитель", "Производитель", 20, Ложь);
	КонецЕсли;

	Для Номер = 1 По 3 Цикл
		ДобавитьПолеКаталога(Каталог, "Свойство" + Номер, "Доп. свойство " + Номер, 20, Ложь);
	КонецЦикла;

	Возврат Каталог;

КонецФункции

Функция ПолучитьНастройки(НомерПрофиля) Экспорт

	ПустоеСвойство = ПланыВидовХарактеристик.ДополнительныеРеквизитыИСведения.ПустаяСсылка();

	Результат = Новый Структура;
	Результат.Вставить("ТипЦен", Справочники.ВидыЦен.ПустаяСсылка());
	Результат.Вставить("Склады", Новый Массив);
	Результат.Вставить("Группы", Новый Массив);
	Результат.Вставить("ТолькоВНаличии", Ложь);
	Результат.Вставить("ТолькоЗапасы", Истина);
	Результат.Вставить("ЗаголовкиГрупп", Истина);
	Результат.Вставить("ИсточникНаименования", "Наименование");
	Результат.Вставить("СвойствоНаименования", ПустоеСвойство);
	Результат.Вставить("Колонки", Новый Массив);
	Результат.Вставить("УчетнаяЗапись", Справочники.УчетныеЗаписиЭлектроннойПочты.ПустаяСсылка());
	Результат.Вставить("Получатели", "");
	Результат.Вставить("Тема", "Прайс-лист от [Дата]");
	Результат.Вставить("ТекстПисьма", "Добрый день! Актуальный прайс-лист во вложении.");
	Результат.Вставить("Формат", "xlsx");

	Сохраненные = ХранилищеОбщихНастроек.Загрузить("ПрайсЛистыПоРасписанию",
		"Профиль" + НомерПрофиля, , ИмяПользователяХранилища());

	Если ТипЗнч(Сохраненные) = Тип("Структура") Тогда
		ЗаполнитьЗначенияСвойств(Результат, Сохраненные);
	КонецЕсли;

	Результат.Колонки = СобратьКолонки(Результат.Колонки, КаталогПолей());

	Возврат Результат;

КонецФункции

Процедура СохранитьНастройки(НомерПрофиля, Настройки) Экспорт

	ХранилищеОбщихНастроек.Сохранить("ПрайсЛистыПоРасписанию",
		"Профиль" + НомерПрофиля, Настройки, , ИмяПользователяХранилища());

КонецПроцедуры

Процедура ОтправитьПрайс(Настройки) Экспорт

	Если Не ЗначениеЗаполнено(Настройки.УчетнаяЗапись) Тогда
		ВызватьИсключение "Не указана учетная запись электронной почты";
	КонецЕсли;
	Если ПустаяСтрока(Настройки.Получатели) Тогда
		ВызватьИсключение "Не указаны получатели";
	КонецЕсли;

	Попытка
		ТабДок = СформироватьПрайс(Настройки);

		Если Настройки.Формат = "pdf" Тогда
			ТипФайла = ТипФайлаТабличногоДокумента.PDF;
			Расширение = "pdf";
		Иначе
			ТипФайла = ТипФайлаТабличногоДокумента.XLSX;
			Расширение = "xlsx";
		КонецЕсли;

		ДатаСтрока = Формат(ТекущаяДата(), "ДФ=dd.MM.yyyy");

		ВремФайл = ПолучитьИмяВременногоФайла(Расширение);
		ТабДок.Записать(ВремФайл, ТипФайла);
		Данные = Новый ДвоичныеДанные(ВремФайл);
		УдалитьФайлы(ВремФайл);
		Адрес = ПоместитьВоВременноеХранилище(Данные, Новый УникальныйИдентификатор);

		Вложение = Новый Структура;
		Вложение.Вставить("Представление", "Прайс-лист " + ДатаСтрока + "." + Расширение);
		Вложение.Вставить("АдресВоВременномХранилище", Адрес);
		Вложения = Новый Массив;
		Вложения.Добавить(Вложение);

		ПараметрыПисьма = Новый Структура;
		ПараметрыПисьма.Вставить("Кому", Настройки.Получатели);
		ПараметрыПисьма.Вставить("Тема", СтрЗаменить(Настройки.Тема, "[Дата]", ДатаСтрока));
		ПараметрыПисьма.Вставить("Тело", Настройки.ТекстПисьма);
		ПараметрыПисьма.Вставить("Вложения", Вложения);

		РаботаСПочтовымиСообщениями.ОтправитьПочтовоеСообщение(Настройки.УчетнаяЗапись, ПараметрыПисьма);

		ЗаписьЖурналаРегистрации("Прайс-листы по расписанию", УровеньЖурналаРегистрации.Информация, ,
			, "Отправлено: " + Настройки.Получатели);
	Исключение
		ЗаписьЖурналаРегистрации("Прайс-листы по расписанию", УровеньЖурналаРегистрации.Ошибка, ,
			, ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
		ВызватьИсключение;
	КонецПопытки;

КонецПроцедуры

Функция СформироватьПрайс(Настройки) Экспорт

	Линия = Новый Линия(ТипЛинииЯчейкиТабличногоДокумента.Сплошная, 1);
	Каталог = КаталогПолей();

	Если Не ЗначениеЗаполнено(Настройки.ТипЦен) Тогда
		ВызватьИсключение "Не указан вид цен";
	КонецЕсли;

	// --- Какие колонки нужны ---
	ВыбранныеКолонки = Новый Массив;
	Для Каждого Колонка Из Настройки.Колонки Цикл
		Если Колонка.Использовать Тогда
			ВыбранныеКолонки.Добавить(Колонка);
		КонецЕсли;
	КонецЦикла;
	Если ВыбранныеКолонки.Количество() = 0 Тогда
		ВызватьИсключение "Не выбрано ни одной колонки";
	КонецЕсли;

	Свойства = Новый Соответствие;
	НужныОстатки = Настройки.ТолькоВНаличии;

	Для Каждого Колонка Из ВыбранныеКолонки Цикл
		Если Колонка.Поле = "Остаток" Тогда
			НужныОстатки = Истина;
		ИначеЕсли СтрНачинаетсяС(Колонка.Поле, "Свойство") Тогда
			Если Не ЗначениеЗаполнено(Колонка.Свойство) Тогда
				ВызватьИсключение "Для колонки """ + Колонка.Заголовок + """ не выбрано дополнительное свойство";
			КонецЕсли;
			Свойства.Вставить(Колонка.Поле, Колонка.Свойство);
		КонецЕсли;
	КонецЦикла;

	Если Настройки.ИсточникНаименования = "Свойство" Тогда
		Если Не ЗначениеЗаполнено(Настройки.СвойствоНаименования) Тогда
			ВызватьИсключение "Не выбрано свойство, из которого брать наименование";
		КонецЕсли;
		Свойства.Вставить("СвойствоИмя", Настройки.СвойствоНаименования);
	КонецЕсли;

	Если Настройки.ТолькоЗапасы
		И Метаданные.Справочники.Номенклатура.Реквизиты.Найти("ТипНоменклатуры") = Неопределено Тогда
		ВызватьИсключение "У номенклатуры нет реквизита ТипНоменклатуры. Снимите галочку ""Только товары""";
	КонецЕсли;

	// --- Запрос ---
	Запрос = Новый Запрос;

	Поля = Новый Массив;
	Поля.Добавить("ЕСТЬNULL(Ном.Родитель.Наименование, &ПустаяСтрока) КАК Группа");
	Поля.Добавить("Ном.Артикул КАК Артикул");
	Поля.Добавить("Ном.Наименование КАК Наименование");
	Поля.Добавить("Ном.НаименованиеПолное КАК НаименованиеПолное");
	Поля.Добавить("ЕСТЬNULL(Цены.Характеристика.Наименование, &ПустаяСтрока) КАК Характеристика");
	Поля.Добавить("ЕСТЬNULL(Ном.ЕдиницаИзмерения.Наименование, &ПустаяСтрока) КАК Единица");
	Поля.Добавить("Цены.Цена КАК Цена");
	Если НужныОстатки Тогда
		Поля.Добавить("ЕСТЬNULL(Остатки.Остаток, 0) КАК Остаток");
	КонецЕсли;
	Если Каталог.Найти("Производитель", "Поле") <> Неопределено Тогда
		Поля.Добавить("Ном.Производитель КАК Производитель");
	КонецЕсли;
	Для Каждого Элемент Из Свойства Цикл
		Поля.Добавить("Доп_" + Элемент.Ключ + ".Значение КАК " + Элемент.Ключ);
	КонецЦикла;

	Текст = "ВЫБРАТЬ " + СтрСоединить(Поля, ", ");
	Текст = Текст + " ИЗ РегистрСведений.ЦеныНоменклатуры.СрезПоследних(&Дата, ВидЦен = &ТипЦен) КАК Цены";
	Текст = Текст + " ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.Номенклатура КАК Ном ПО Цены.Номенклатура = Ном.Ссылка";

	Для Каждого Элемент Из Свойства Цикл
		Имя = Элемент.Ключ;
		Текст = Текст + " ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Номенклатура.ДополнительныеРеквизиты КАК Доп_" + Имя
			+ " ПО Доп_" + Имя + ".Ссылка = Ном.Ссылка И Доп_" + Имя + ".Свойство = &П_" + Имя;
		Запрос.УстановитьПараметр("П_" + Имя, Элемент.Значение);
	КонецЦикла;

	Если НужныОстатки Тогда
		УсловиеСклада = ?(Настройки.Склады.Количество() > 0, "СтруктурнаяЕдиница В (&Склады)", "");
		Текст = Текст + " ЛЕВОЕ СОЕДИНЕНИЕ (ВЫБРАТЬ Ост.Номенклатура КАК Номенклатура, Ост.Характеристика КАК Характеристика,"
			+ " СУММА(Ост.КоличествоОстаток) КАК Остаток"
			+ " ИЗ РегистрНакопления.ЗапасыНаСкладах.Остатки(&Дата, " + УсловиеСклада + ") КАК Ост"
			+ " СГРУППИРОВАТЬ ПО Ост.Номенклатура, Ост.Характеристика) КАК Остатки"
			+ " ПО Остатки.Номенклатура = Цены.Номенклатура И Остатки.Характеристика = Цены.Характеристика";
		Запрос.УстановитьПараметр("Склады", Настройки.Склады);
	КонецЕсли;

	Условия = Новый Массив;
	Условия.Добавить("НЕ Ном.ПометкаУдаления");
	Условия.Добавить("НЕ Ном.ЭтоГруппа");
	Условия.Добавить("Цены.Цена > 0");
	Условия.Добавить("Цены.Актуальность");
	Если Настройки.ТолькоЗапасы Тогда
		Условия.Добавить("Ном.ТипНоменклатуры = ЗНАЧЕНИЕ(Перечисление.ТипыНоменклатуры.Запас)");
	КонецЕсли;
	Если Настройки.Группы.Количество() > 0 Тогда
		Условия.Добавить("Ном.Ссылка В ИЕРАРХИИ(&Группы)");
		Запрос.УстановитьПараметр("Группы", Настройки.Группы);
	КонецЕсли;
	Если Настройки.ТолькоВНаличии Тогда
		Условия.Добавить("ЕСТЬNULL(Остатки.Остаток, 0) > 0");
	КонецЕсли;

	Текст = Текст + " ГДЕ " + СтрСоединить(Условия, " И ");

	Запрос.Текст = Текст;
	Запрос.УстановитьПараметр("Дата", ТекущаяДата());
	Запрос.УстановитьПараметр("ТипЦен", Настройки.ТипЦен);
	Запрос.УстановитьПараметр("ПустаяСтрока", "");

	Таблица = Запрос.Выполнить().Выгрузить();

	// --- Выбор наименования ---
	Таблица.Колонки.Добавить("ИмяВПрайсе");
	Для Каждого СтрокаТ Из Таблица Цикл
		Имя = СтрокаТ.Наименование;
		Если Настройки.ИсточникНаименования = "Полное" Тогда
			Если Не ПустаяСтрока(СтрокаТ.НаименованиеПолное) Тогда
				Имя = СтрокаТ.НаименованиеПолное;
			КонецЕсли;
		ИначеЕсли Настройки.ИсточникНаименования = "Свойство" Тогда
			ЗначениеСвойства = ВСтроку(СтрокаТ.СвойствоИмя);
			Если Не ПустаяСтрока(ЗначениеСвойства) Тогда
				Имя = ЗначениеСвойства;
			КонецЕсли;
		КонецЕсли;
		СтрокаТ.ИмяВПрайсе = Имя;
	КонецЦикла;

	Если Настройки.ЗаголовкиГрупп Тогда
		Таблица.Сортировать("Группа, ИмяВПрайсе");
	Иначе
		Таблица.Сортировать("ИмяВПрайсе");
	КонецЕсли;

	// --- Вывод ---
	ЧислоКолонок = ВыбранныеКолонки.Количество();

	ТабДок = Новый ТабличныйДокумент;
	ТабДок.ОриентацияСтраницы = ОриентацияСтраницы.Портрет;
	ТабДок.ПолеСлева = 10;
	ТабДок.ПолеСправа = 10;
	ТабДок.АвтоМасштаб = Истина;

	НомерСтроки = 1;
	ТабДок.Область(НомерСтроки, 1).Текст = "Прайс-лист на " + Формат(ТекущаяДата(), "ДФ=dd.MM.yyyy")
		+ " (" + Настройки.ТипЦен + ")";
	ТабДок.Область(НомерСтроки, 1).Шрифт = Новый Шрифт(, 12, Истина);
	НомерСтроки = НомерСтроки + 2;

	Для Индекс = 0 По ЧислоКолонок - 1 Цикл
		Колонка = ВыбранныеКолонки[Индекс];
		Ячейка = ТабДок.Область(НомерСтроки, Индекс + 1);
		Ячейка.Текст = Колонка.Заголовок;
		Ячейка.Шрифт = Новый Шрифт(, , Истина);
		Ячейка.ЦветФона = Новый Цвет(220, 220, 220);
		Ячейка.Обвести(Линия, Линия, Линия, Линия);

		Ширина = 20;
		СтрокаКаталога = Каталог.Найти(Колонка.Поле, "Поле");
		Если СтрокаКаталога <> Неопределено Тогда
			Ширина = СтрокаКаталога.Ширина;
		КонецЕсли;
		ТабДок.Область(, Индекс + 1, , Индекс + 1).ШиринаКолонки = Ширина;
	КонецЦикла;
	ТабДок.ФиксацияСверху = НомерСтроки;
	НомерСтроки = НомерСтроки + 1;

	ТекущаяГруппа = Неопределено;

	Для Каждого СтрокаТ Из Таблица Цикл

		Если Настройки.ЗаголовкиГрупп И СтрокаТ.Группа <> ТекущаяГруппа Тогда
			ТекущаяГруппа = СтрокаТ.Группа;
			Если Не ПустаяСтрока(ТекущаяГруппа) Тогда
				Область = ТабДок.Область(НомерСтроки, 1, НомерСтроки, ЧислоКолонок);
				Область.Объединить();
				Область.Текст = ТекущаяГруппа;
				Область.Шрифт = Новый Шрифт(, , Истина);
				Область.ЦветФона = Новый Цвет(240, 240, 240);
				НомерСтроки = НомерСтроки + 1;
			КонецЕсли;
		КонецЕсли;

		Для Индекс = 0 По ЧислоКолонок - 1 Цикл
			Колонка = ВыбранныеКолонки[Индекс];
			Ячейка = ТабДок.Область(НомерСтроки, Индекс + 1);

			Если Колонка.Поле = "Цена" Тогда
				Ячейка.Значение = СтрокаТ.Цена;
				Ячейка.Формат = "ЧДЦ=2";
				Ячейка.ГоризонтальноеПоложение = ГоризонтальноеПоложение.Право;
			ИначеЕсли Колонка.Поле = "Остаток" Тогда
				Ячейка.Значение = Окр(СтрокаТ.Остаток, 3);
				Ячейка.ГоризонтальноеПоложение = ГоризонтальноеПоложение.Право;
			ИначеЕсли Колонка.Поле = "Наименование" Тогда
				Ячейка.Текст = СтрокаТ.ИмяВПрайсе;
			Иначе
				Ячейка.Текст = ВСтроку(СтрокаТ[Колонка.Поле]);
			КонецЕсли;
		КонецЦикла;

		НомерСтроки = НомерСтроки + 1;

	КонецЦикла;

	Возврат ТабДок;

КонецФункции

#КонецОбласти

#Область СлужебныеПроцедурыИФункции

Функция ИмяПользователяХранилища()
	Возврат "ПрайсЛистыПоРасписанию_Общие";
КонецФункции

Функция ВСтроку(Значение)
	Если Значение = Null Или Значение = Неопределено Тогда
		Возврат "";
	КонецЕсли;
	Возврат СокрЛП(Строка(Значение));
КонецФункции

Процедура ДобавитьПолеКаталога(Каталог, Поле, Название, Ширина, ПоУмолчанию)
	Новая = Каталог.Добавить();
	Новая.Поле = Поле;
	Новая.Название = Название;
	Новая.Ширина = Ширина;
	Новая.ПоУмолчанию = ПоУмолчанию;
КонецПроцедуры

Функция НоваяКолонка(Поле, Использовать, Заголовок, Свойство)
	Результат = Новый Структура;
	Результат.Вставить("Поле", Поле);
	Результат.Вставить("Использовать", Использовать);
	Результат.Вставить("Заголовок", Заголовок);
	Результат.Вставить("Свойство", Свойство);
	Возврат Результат;
КонецФункции

// Сохраненный порядок колонок + новые колонки из каталога в конец.
Функция СобратьКолонки(Сохраненные, Каталог)

	Результат = Новый Массив;
	Добавленные = Новый Соответствие;
	ПустоеСвойство = ПланыВидовХарактеристик.ДополнительныеРеквизитыИСведения.ПустаяСсылка();

	Для Каждого Колонка Из Сохраненные Цикл
		Если Каталог.Найти(Колонка.Поле, "Поле") = Неопределено Или Добавленные[Колонка.Поле] <> Неопределено Тогда
			Продолжить;
		КонецЕсли;
		Добавленные.Вставить(Колонка.Поле, Истина);
		Результат.Добавить(НоваяКолонка(Колонка.Поле, Колонка.Использовать, Колонка.Заголовок, Колонка.Свойство));
	КонецЦикла;

	Для Каждого СтрокаКаталога Из Каталог Цикл
		Если Добавленные[СтрокаКаталога.Поле] = Неопределено Тогда
			Результат.Добавить(НоваяКолонка(СтрокаКаталога.Поле, СтрокаКаталога.ПоУмолчанию,
				СтрокаКаталога.Название, ПустоеСвойство));
		КонецЕсли;
	КонецЦикла;

	Возврат Результат;

КонецФункции

#КонецОбласти
Блок 2. Модуль формы
bsl
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)

	СоздатьРеквизиты();
	СоздатьЭлементы();
	ЭтаФорма.НомерПрофиля = 1;
	ЗагрузитьНастройкиНаСервере();

КонецПроцедуры

#Область Команды

&НаКлиенте
Процедура НомерПрофиляПриИзменении(Элемент)
	ЗагрузитьНастройкиНаСервере();
КонецПроцедуры

&НаКлиенте
Процедура СохранитьНастройки(Команда)
	СохранитьНаСервере();
	ПоказатьОповещениеПользователя("Настройки сохранены");
КонецПроцедуры

&НаКлиенте
Процедура ПоказатьПредпросмотр(Команда)
	ПредпросмотрНаСервере();
	Элементы.ГруппаСтраниц.ТекущаяСтраница = Элементы.СтраницаПредпросмотр;
КонецПроцедуры

&НаКлиенте
Процедура ОтправитьСейчас(Команда)
	СохранитьНаСервере();
	ОтправитьНаСервере();
	ПоказатьОповещениеПользователя("Прайс-лист отправлен");
КонецПроцедуры

&НаКлиенте
Процедура КолонкаВверх(Команда)
	СдвинутьКолонку(-1);
КонецПроцедуры

&НаКлиенте
Процедура КолонкаВниз(Команда)
	СдвинутьКолонку(1);
КонецПроцедуры

&НаКлиенте
Процедура СдвинутьКолонку(Смещение)

	Данные = Элементы.Колонки.ТекущиеДанные;
	Если Данные = Неопределено Тогда
		Возврат;
	КонецЕсли;

	КолонкиФормы = ЭтаФорма.Колонки;
	Индекс = КолонкиФормы.Индекс(Данные);
	НовыйИндекс = Индекс + Смещение;
	Если НовыйИндекс < 0 Или НовыйИндекс >= КолонкиФормы.Количество() Тогда
		Возврат;
	КонецЕсли;

	КолонкиФормы.Сдвинуть(Индекс, Смещение);
	Элементы.Колонки.ТекущаяСтрока = Данные.ПолучитьИдентификатор();

КонецПроцедуры

#КонецОбласти

#Область РаботаНаСервере

&НаСервере
Функция НастройкиИзФормы()

	Результат = Новый Структура;
	Результат.Вставить("ТипЦен", ЭтаФорма.ТипЦен);
	Результат.Вставить("ТолькоВНаличии", ЭтаФорма.ТолькоВНаличии);
	Результат.Вставить("ТолькоЗапасы", ЭтаФорма.ТолькоЗапасы);
	Результат.Вставить("ЗаголовкиГрупп", ЭтаФорма.ЗаголовкиГрупп);
	Результат.Вставить("ИсточникНаименования", ЭтаФорма.ИсточникНаименования);
	Результат.Вставить("СвойствоНаименования", ЭтаФорма.СвойствоНаименования);
	Результат.Вставить("УчетнаяЗапись", ЭтаФорма.УчетнаяЗапись);
	Результат.Вставить("Получатели", ЭтаФорма.Получатели);
	Результат.Вставить("Тема", ЭтаФорма.Тема);
	Результат.Вставить("ТекстПисьма", ЭтаФорма.ТекстПисьма);
	Результат.Вставить("Формат", ЭтаФорма.Формат);

	Склады = Новый Массив;
	Для Каждого Элемент Из ЭтаФорма.Склады Цикл
		Если Элемент.Пометка Тогда
			Склады.Добавить(Элемент.Значение);
		КонецЕсли;
	КонецЦикла;
	Результат.Вставить("Склады", Склады);

	Группы = Новый Массив;
	Для Каждого СтрокаГруппы Из ЭтаФорма.ГруппыОтбора Цикл
		Если ЗначениеЗаполнено(СтрокаГруппы.Группа) Тогда
			Группы.Добавить(СтрокаГруппы.Группа);
		КонецЕсли;
	КонецЦикла;
	Результат.Вставить("Группы", Группы);

	Колонки = Новый Массив;
	Для Каждого СтрокаКолонки Из ЭтаФорма.Колонки Цикл
		Колонка = Новый Структура;
		Колонка.Вставить("Поле", СтрокаКолонки.Поле);
		Колонка.Вставить("Использовать", СтрокаКолонки.Использовать);
		Колонка.Вставить("Заголовок", СтрокаКолонки.Заголовок);
		Колонка.Вставить("Свойство", СтрокаКолонки.Свойство);
		Колонки.Добавить(Колонка);
	КонецЦикла;
	Результат.Вставить("Колонки", Колонки);

	Возврат Результат;

КонецФункции

&НаСервере
Процедура ЗагрузитьНастройкиНаСервере()

	ОбъектОбработки = РеквизитФормыВЗначение("Объект");
	Настройки = ОбъектОбработки.ПолучитьНастройки(ЭтаФорма.НомерПрофиля);
	Каталог = ОбъектОбработки.КаталогПолей();

	ЭтаФорма.ТипЦен = Настройки.ТипЦен;
	ЭтаФорма.ТолькоВНаличии = Настройки.ТолькоВНаличии;
	ЭтаФорма.ТолькоЗапасы = Настройки.ТолькоЗапасы;
	ЭтаФорма.ЗаголовкиГрупп = Настройки.ЗаголовкиГрупп;
	ЭтаФорма.ИсточникНаименования = Настройки.ИсточникНаименования;
	ЭтаФорма.СвойствоНаименования = Настройки.СвойствоНаименования;
	ЭтаФорма.УчетнаяЗапись = Настройки.УчетнаяЗапись;
	ЭтаФорма.Получатели = Настройки.Получатели;
	ЭтаФорма.Тема = Настройки.Тема;
	ЭтаФорма.ТекстПисьма = Настройки.ТекстПисьма;
	ЭтаФорма.Формат = Настройки.Формат;

	// Склады: все склады списком, отмечены выбранные
	ЭтаФорма.Склады.Очистить();
	ЗапросСкладов = Новый Запрос;
	ЗапросСкладов.Текст = "ВЫБРАТЬ Ссылка КАК Склад ИЗ Справочник.СтруктурныеЕдиницы
		| ГДЕ НЕ ПометкаУдаления УПОРЯДОЧИТЬ ПО Наименование";
	Выборка = ЗапросСкладов.Выполнить().Выбрать();
	Пока Выборка.Следующий() Цикл
		Выбран = Настройки.Склады.Найти(Выборка.Склад) <> Неопределено;
		ЭтаФорма.Склады.Добавить(Выборка.Склад, Строка(Выборка.Склад), Выбран);
	КонецЦикла;

	ЭтаФорма.ГруппыОтбора.Очистить();
	Для Каждого Группа Из Настройки.Группы Цикл
		ЭтаФорма.ГруппыОтбора.Добавить().Группа = Группа;
	КонецЦикла;

	ЭтаФорма.Колонки.Очистить();
	Для Каждого Колонка Из Настройки.Колонки Цикл
		Новая = ЭтаФорма.Колонки.Добавить();
		Новая.Поле = Колонка.Поле;
		Новая.Использовать = Колонка.Использовать;
		Новая.Заголовок = Колонка.Заголовок;
		Новая.Свойство = Колонка.Свойство;
		Новая.Название = Каталог.Найти(Колонка.Поле, "Поле").Название;
	КонецЦикла;

КонецПроцедуры

&НаСервере
Процедура СохранитьНаСервере()
	РеквизитФормыВЗначение("Объект").СохранитьНастройки(ЭтаФорма.НомерПрофиля, НастройкиИзФормы());
КонецПроцедуры

&НаСервере
Процедура ОтправитьНаСервере()
	РеквизитФормыВЗначение("Объект").ОтправитьПрайс(НастройкиИзФормы());
КонецПроцедуры

&НаСервере
Процедура ПредпросмотрНаСервере()
	ТабДок = РеквизитФормыВЗначение("Объект").СформироватьПрайс(НастройкиИзФормы());
	ЗначениеВРеквизитФормы(ТабДок, "Предпросмотр");
КонецПроцедуры

#КонецОбласти

#Область ПостроениеФормы

&НаСервере
Процедура СоздатьРеквизиты()

	ТБулево = Новый ОписаниеТипов("Булево");
	ТСтрока20 = Новый ОписаниеТипов("Строка", , Новый КвалификаторыСтроки(20));
	ТСтрока30 = Новый ОписаниеТипов("Строка", , Новый КвалификаторыСтроки(30));
	ТСтрока50 = Новый ОписаниеТипов("Строка", , Новый КвалификаторыСтроки(50));
	ТСтрока100 = Новый ОписаниеТипов("Строка", , Новый КвалификаторыСтроки(100));
	ТСтрока200 = Новый ОписаниеТипов("Строка", , Новый КвалификаторыСтроки(200));
	ТСтрока500 = Новый ОписаниеТипов("Строка", , Новый КвалификаторыСтроки(500));
	ТСтрокаБезОграничений = Новый ОписаниеТипов("Строка", , Новый КвалификаторыСтроки(0));
	ТСвойство = Новый ОписаниеТипов("ПланВидовХарактеристикСсылка.ДополнительныеРеквизитыИСведения");

	Реквизиты = Новый Массив;
	Реквизиты.Добавить(Новый РеквизитФормы("НомерПрофиля",
		Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(1, 0)), "", "Профиль рассылки"));
	Реквизиты.Добавить(Новый РеквизитФормы("ТипЦен",
		Новый ОписаниеТипов("СправочникСсылка.ВидыЦен"), "", "Вид цен"));
	Реквизиты.Добавить(Новый РеквизитФормы("ТолькоВНаличии", ТБулево, "", "Только то, что есть в наличии"));
	Реквизиты.Добавить(Новый РеквизитФормы("ТолькоЗапасы", ТБулево, "", "Только товары (без услуг и работ)"));
	Реквизиты.Добавить(Новый РеквизитФормы("ЗаголовкиГрупп", ТБулево, "", "Выводить названия групп"));
	Реквизиты.Добавить(Новый РеквизитФормы("ИсточникНаименования", ТСтрока20, "", "Откуда брать наименование"));
	Реквизиты.Добавить(Новый РеквизитФормы("СвойствоНаименования", ТСвойство, "", "Свойство с наименованием"));
	Реквизиты.Добавить(Новый РеквизитФормы("УчетнаяЗапись",
		Новый ОписаниеТипов("СправочникСсылка.УчетныеЗаписиЭлектроннойПочты"), "", "Учетная запись почты"));
	Реквизиты.Добавить(Новый РеквизитФормы("Получатели", ТСтрока500, "", "Получатели (через ;)"));
	Реквизиты.Добавить(Новый РеквизитФормы("Тема", ТСтрока200, "", "Тема письма"));
	Реквизиты.Добавить(Новый РеквизитФормы("ТекстПисьма", ТСтрокаБезОграничений, "", "Текст письма"));
	Реквизиты.Добавить(Новый РеквизитФормы("Формат", Новый ОписаниеТипов("Строка", , Новый КвалификаторыСтроки(4)),
		"", "Формат файла"));
	Реквизиты.Добавить(Новый РеквизитФормы("Склады", Новый ОписаниеТипов("СписокЗначений"), "", "Склады"));
	Реквизиты.Добавить(Новый РеквизитФормы("Предпросмотр", Новый ОписаниеТипов("ТабличныйДокумент"), "", "Предпросмотр"));

	Реквизиты.Добавить(Новый РеквизитФормы("ГруппыОтбора", Новый ОписаниеТипов("ТаблицаЗначений"), "", "Группы"));
	Реквизиты.Добавить(Новый РеквизитФормы("Группа",
		Новый ОписаниеТипов("СправочникСсылка.Номенклатура"), "ГруппыОтбора", "Группа"));

	Реквизиты.Добавить(Новый РеквизитФормы("Колонки", Новый ОписаниеТипов("ТаблицаЗначений"), "", "Колонки"));
	Реквизиты.Добавить(Новый РеквизитФормы("Использовать", ТБулево, "Колонки", "Выводить"));
	Реквизиты.Добавить(Новый РеквизитФормы("Поле", ТСтрока30, "Колонки", "Поле"));
	Реквизиты.Добавить(Новый РеквизитФормы("Название", ТСтрока50, "Колонки", "Что это"));
	Реквизиты.Добавить(Новый РеквизитФормы("Заголовок", ТСтрока100, "Колонки", "Заголовок в прайсе"));
	Реквизиты.Добавить(Новый РеквизитФормы("Свойство", ТСвойство, "Колонки", "Доп. свойство (для «Доп. свойство N»)"));

	ИзменитьРеквизиты(Реквизиты);

КонецПроцедуры

&НаСервере
Процедура СоздатьЭлементы()

	// Кнопки сверху
	ГруппаКнопок = ДобавитьГруппу("ГруппаКнопок", Неопределено, ВидГруппыФормы.ОбычнаяГруппа, "Действия");
	ГруппаКнопок.Группировка = ГруппировкаГруппыФормы.Горизонтальная;
	ГруппаКнопок.ОтображатьЗаголовок = Ложь;
	ДобавитьКнопку("КнопкаСохранить", "СохранитьНастройки", "Сохранить настройки", ГруппаКнопок);
	ДобавитьКнопку("КнопкаПредпросмотр", "ПоказатьПредпросмотр", "Предпросмотр", ГруппаКнопок);
	ДобавитьКнопку("КнопкаОтправить", "ОтправитьСейчас", "Отправить сейчас", ГруппаКнопок);

	ГруппаСтраниц = ДобавитьГруппу("ГруппаСтраниц", Неопределено, ВидГруппыФормы.Страницы, "Страницы");

	// ---------- Основное ----------
	Страница = ДобавитьГруппу("СтраницаОсновное", ГруппаСтраниц, ВидГруппыФормы.Страница, "Основное");

	Поле = ДобавитьПоле("НомерПрофиля", Страница, ВидПоляФормы.ПолеВвода);
	Поле.РежимВыбораИзСписка = Истина;
	Для Номер = 1 По 3 Цикл
		Поле.СписокВыбора.Добавить(Номер);
	КонецЦикла;
	Поле.УстановитьДействие("ПриИзменении", "НомерПрофиляПриИзменении");

	ДобавитьПоле("ТипЦен", Страница, ВидПоляФормы.ПолеВвода);
	ДобавитьПоле("ТолькоВНаличии", Страница, ВидПоляФормы.ПолеФлажка);
	ДобавитьПоле("ТолькоЗапасы", Страница, ВидПоляФормы.ПолеФлажка);
	ДобавитьПоле("ЗаголовкиГрупп", Страница, ВидПоляФормы.ПолеФлажка);

	Поле = ДобавитьПоле("ИсточникНаименования", Страница, ВидПоляФормы.ПолеВвода);
	Поле.РежимВыбораИзСписка = Истина;
	Поле.СписокВыбора.Добавить("Наименование", "Наименование (краткое)");
	Поле.СписокВыбора.Добавить("Полное", "Полное наименование (для печати)");
	Поле.СписокВыбора.Добавить("Свойство", "Дополнительное свойство (например, для сайта)");

	ДобавитьПоле("СвойствоНаименования", Страница, ВидПоляФормы.ПолеВвода);

	// ---------- Колонки ----------
	Страница = ДобавитьГруппу("СтраницаКолонки", ГруппаСтраниц, ВидГруппыФормы.Страница, "Колонки");
	ДобавитьНадпись("НадписьКолонки", Страница,
		"Отметьте нужные колонки, порядок меняйте стрелками. Строки «Доп. свойство N» — выберите справа нужное свойство.");

	ГруппаСтрелок = ДобавитьГруппу("ГруппаСтрелок", Страница, ВидГруппыФормы.ОбычнаяГруппа, "Порядок");
	ГруппаСтрелок.Группировка = ГруппировкаГруппыФормы.Горизонтальная;
	ГруппаСтрелок.ОтображатьЗаголовок = Ложь;
	ДобавитьКнопку("КнопкаВверх", "КолонкаВверх", "Вверх", ГруппаСтрелок);
	ДобавитьКнопку("КнопкаВниз", "КолонкаВниз", "Вниз", ГруппаСтрелок);

	Таблица = ДобавитьТаблицу("Колонки", Страница);
	Таблица.ИзменятьСоставСтрок = Ложь;
	Поле = ДобавитьПолеТаблицы("КолонкиИспользовать", "Колонки.Использовать", Таблица, ВидПоляФормы.ПолеФлажка);
	Поле = ДобавитьПолеТаблицы("КолонкиНазвание", "Колонки.Название", Таблица, ВидПоляФормы.ПолеВвода);
	Поле.ТолькоПросмотр = Истина;
	ДобавитьПолеТаблицы("КолонкиЗаголовок", "Колонки.Заголовок", Таблица, ВидПоляФормы.ПолеВвода);
	ДобавитьПолеТаблицы("КолонкиСвойство", "Колонки.Свойство", Таблица, ВидПоляФормы.ПолеВвода);

	// ---------- Отбор ----------
	Страница = ДобавитьГруппу("СтраницаОтбор", ГруппаСтраниц, ВидГруппыФормы.Страница, "Отбор");

	ДобавитьНадпись("НадписьСклады", Страница,
		"Склады, по которым считается остаток (если ничего не отмечено — по всем):");
	Таблица = ДобавитьТаблицу("Склады", Страница);
	Таблица.ИзменятьСоставСтрок = Ложь;
	Таблица.Высота = 6;
	ДобавитьПолеТаблицы("СкладыПометка", "Склады.Пометка", Таблица, ВидПоляФормы.ПолеФлажка);
	Поле = ДобавитьПолеТаблицы("СкладыПредставление", "Склады.Представление", Таблица, ВидПоляФормы.ПолеВвода);
	Поле.ТолькоПросмотр = Истина;

	ДобавитьНадпись("НадписьГруппы", Страница,
		"Показывать только эти группы номенклатуры (пусто — весь каталог):");
	Таблица = ДобавитьТаблицу("ГруппыОтбора", Страница);
	Таблица.Высота = 6;
	Поле = ДобавитьПолеТаблицы("ГруппыОтбораГруппа", "ГруппыОтбора.Группа", Таблица, ВидПоляФормы.ПолеВвода);
	Поле.ВыборГруппИЭлементов = ИспользованиеГруппИЭлементов.Группы;

	// ---------- Письмо ----------
	Страница = ДобавитьГруппу("СтраницаПисьмо", ГруппаСтраниц, ВидГруппыФормы.Страница, "Письмо");
	ДобавитьПоле("УчетнаяЗапись", Страница, ВидПоляФормы.ПолеВвода);
	ДобавитьПоле("Получатели", Страница, ВидПоляФормы.ПолеВвода);
	ДобавитьПоле("Тема", Страница, ВидПоляФормы.ПолеВвода);
	Поле = ДобавитьПоле("ТекстПисьма", Страница, ВидПоляФормы.ПолеВвода);
	Поле.МногострочныйРежим = Истина;
	Поле.Высота = 4;
	Поле = ДобавитьПоле("Формат", Страница, ВидПоляФормы.ПолеВвода);
	Поле.РежимВыбораИзСписка = Истина;
	Поле.СписокВыбора.Добавить("xlsx");
	Поле.СписокВыбора.Добавить("pdf");

	// ---------- Предпросмотр ----------
	Страница = ДобавитьГруппу("СтраницаПредпросмотр", ГруппаСтраниц, ВидГруппыФормы.Страница, "Предпросмотр");
	Поле = ДобавитьПоле("Предпросмотр", Страница, ВидПоляФормы.ПолеТабличногоДокумента);
	Поле.ОтображатьЗаголовок = Ложь;

КонецПроцедуры

&НаСервере
Функция ДобавитьЭлемент(Имя, ТипЭлемента, Родитель)
	Если Родитель = Неопределено Тогда
		Возврат Элементы.Добавить(Имя, ТипЭлемента);
	КонецЕсли;
	Возврат Элементы.Добавить(Имя, ТипЭлемента, Родитель);
КонецФункции

&НаСервере
Функция ДобавитьГруппу(Имя, Родитель, Вид, Заголовок)
	Группа = ДобавитьЭлемент(Имя, Тип("ГруппаФормы"), Родитель);
	Группа.Вид = Вид;
	Группа.Заголовок = Заголовок;
	Возврат Группа;
КонецФункции

&НаСервере
Функция ДобавитьПоле(ИмяРеквизита, Родитель, Вид)
	Поле = ДобавитьЭлемент(ИмяРеквизита, Тип("ПолеФормы"), Родитель);
	Поле.Вид = Вид;
	Поле.ПутьКДанным = ИмяРеквизита;
	Возврат Поле;
КонецФункции

&НаСервере
Функция ДобавитьПолеТаблицы(ИмяЭлемента, Путь, Таблица, Вид)
	Поле = ДобавитьЭлемент(ИмяЭлемента, Тип("ПолеФормы"), Таблица);
	Поле.Вид = Вид;
	Поле.ПутьКДанным = Путь;
	Возврат Поле;
КонецФункции

&НаСервере
Функция ДобавитьТаблицу(ИмяРеквизита, Родитель)
	Таблица = ДобавитьЭлемент(ИмяРеквизита, Тип("ТаблицаФормы"), Родитель);
	Таблица.ПутьКДанным = ИмяРеквизита;
	Возврат Таблица;
КонецФункции

&НаСервере
Процедура ДобавитьНадпись(Имя, Родитель, Текст)
	Надпись = ДобавитьЭлемент(Имя, Тип("ДекорацияФормы"), Родитель);
	Надпись.Вид = ВидДекорацииФормы.Надпись;
	Надпись.Заголовок = Текст;
КонецПроцедуры

&НаСервере
Процедура ДобавитьКнопку(ИмяКнопки, ИмяКоманды, Заголовок, Родитель)
	Команда = Команды.Добавить(ИмяКоманды);
	Команда.Действие = ИмяКоманды;
	Команда.Заголовок = Заголовок;
	Кнопка = ДобавитьЭлемент(ИмяКнопки, Тип("КнопкаФормы"), Родитель);
	Кнопка.ИмяКоманды = ИмяКоманды;
КонецПроцедуры

#КонецОбласти
Что может не совпасть с вашей УНФ

Я не видел вашу базу, поэтому несколько имён взяты по типовой УНФ:

РегистрНакопления.ЗапасыНаСкладах с измерением СтруктурнаяЕдиница: остатки по складам.
Справочник.СтруктурныеЕдиницы: список складов в форме.
Перечисление.ТипыНоменклатуры.Запас и реквизит ТипНоменклатуры: отсечение услуг.
Табличная часть ДополнительныеРеквизиты у номенклатуры: для «Наименования для сайта» и «Производителя».

Если что-то не совпадёт, при предпросмотре или отправке появится ошибка. Сфотографируйте её, как делали раньше, и я поправлю имя.

Колонка «Производитель» появится в списке, только если такой реквизит есть у номенклатуры. Если его нет, выводите производителя через «Доп. свойство 1», выбрав нужное свойство в таблице колонок.

Ещё два уточнения:

Если «Наименование для сайта» лежит не в дополнительных реквизитах, а в «Дополнительных сведениях», напишите мне, и запрос нужно будет немного переделать.
После того как всё заработает, поставьте расписание на ближайшие 5–10 минут и проверьте, что письмо пришло само. Настройки для регламентного задания читаются из хранилища, и это стоит проверить отдельно от кнопки «Отправить сейчас».

Дальше можно добавить произвольные условия на любой реквизит номенклатуры, скидку или наценку к цене и несколько видов цен в одном прайсе. Скажите, что нужно в первую очередь.