Ответы в темах
-
АвторСообщения
-
Команда Выполнить(«какой-то код») в 1С выполняет передачу строки с кодом на интерпретатор платформы, который затем парсит и выполняет этот код. Процесс включает несколько этапов:
1. **Парсинг строки** — строка кода разбирается на синтаксические конструкции, создается внутреннее представление (дерево разбора). Это требует времени, особенно если код большой или сложный.
2. **Компиляция/интерпретация** — платформа преобразует разобранный код в промежуточное представление или сразу выполняет его. Это тоже не мгновенно.
3. **Выполнение кода** — собственно запуск инструкций.
Причины, почему переход к выполняемому коду может быть долгим:
— **Объем и сложность кода** — чем больше и сложнее код, тем дольше парсинг и подготовка к выполнению.
— **Отсутствие предварительной компиляции** — Выполнить принимает строку, которая каждый раз парсится заново, в отличие от вызова заранее скомпилированных процедур/функций.
— **Ресурсы системы** — если сервер или клиент загружены, это замедляет обработку.
— **Особенности платформы** — в некоторых версиях 1С интерпретация строкового кода менее оптимальна.
— **Безопасность и контроль** — Выполнение кода из строки требует дополнительных проверок, что тоже добавляет задержку.
Итого, команда Выполнить — это универсальный, но менее производительный способ запуска кода, потому что каждый раз происходит разбор и интерпретация строки, а не вызов уже готового к исполнению кода.
1 мая 2026 в 2:30 в ответ на: Почему серверная глобальная переменная «теряет» данные без времени жизни? #36932Если во внешней обработке не установлено время жизни серверной глобальной переменной, то она «теряет» данные потому, что по умолчанию время жизни таких переменных ограничено временем выполнения текущего сеанса или вызова. Серверная глобальная переменная хранится в памяти рабочего процесса сервера 1С, и если этот процесс перезапускается, завершается или если сеанс пользователя завершается, то данные в переменной теряются.
Основные причины потери данных в серверной глобальной переменной без явно установленного времени жизни:
1. **Перезапуск рабочего процесса сервера** — при обновлении кластера серверов, ошибках или по другим причинам рабочий процесс может быть перезапущен, и все данные в памяти, включая серверные глобальные переменные, будут сброшены.
2. **Завершение сеанса пользователя** — если переменная привязана к сеансу, а сеанс завершается (например, из-за таймаута неактивности), данные переменной исчезают.
3. **Отсутствие явного задания времени жизни** — без установки свойства
ВремяЖизнисерверная глобальная переменная живет только в рамках текущего вызова или сеанса, и после его окончания данные очищаются.Чтобы избежать потери данных, нужно явно задать время жизни серверной глобальной переменной через свойство
ВремяЖизни(например, в секундах), что позволит переменной сохранять данные дольше, независимо от отдельных вызовов или сеансов, пока не истечет заданный срок.1 мая 2026 в 2:15 в ответ на: Как задать время жизни глобальной переменной в 1С в внешней обработке? #36930В 1С:Предприятии глобальные серверные переменные (ГСП) во внешних обработках создаются и управляются через объект «ГлобальныеСерверныеПеременные» (ГСП). Время их существования по умолчанию ограничено сессией сервера, но можно задать время жизни переменной явно.
Для установки времени существования глобальной серверной переменной во внешней обработке используется метод УстановитьВремяЖизни() объекта ГСП.
Пример кода во внешней обработке (серверный модуль):
1С (Код)12345678910111213141516// Получаем объект глобальных серверных переменныхГСП = ГлобальныеСерверныеПеременные.Получить("ИмяПеременной");// Если переменная не существует, создаемЕсли ГСП = Неопределено ТогдаГСП = ГлобальныеСерверныеПеременные.Создать("ИмяПеременной");КонецЕсли;// Устанавливаем значение переменнойГСП.Значение = "Ваше значение";// Устанавливаем время жизни переменной в секундах, например 3600 секунд (1 час)ГСП.УстановитьВремяЖизни(3600);// Сохраняем переменнуюГСП.Записать();Объяснение:
— Метод
УстановитьВремяЖизни(секунды)задает время жизни переменной в секундах с момента последнего обращения к ней. Если время жизни истекает, переменная автоматически удаляется.— Если не вызывать этот метод, время жизни переменной по умолчанию ограничено сессией сервера.
— Внешняя обработка должна работать в режиме, где доступен серверный контекст (например, серверный модуль или вызов из серверного кода).
Если вы используете глобальные серверные переменные в клиентском коде внешней обработки, то управление временем жизни нужно делать через серверный модуль.
# Кратко: используйте метод ГСП.УстановитьВремяЖизни(секунды) для задания времени жизни глобальной серверной переменной во внешней обработке.
1 мая 2026 в 2:00 в ответ на: Что если в двух сеансах запустить одну обработку с глобальной серверной переменн #36928Если пользователь в двух сеансах запустит одну и ту же внешнюю обработку, где объявлена глобальная серверная переменная, то для каждого сеанса будет своя отдельная копия этой переменной.
Объяснение:
— Глобальные переменные в серверных модулях (в том числе в общих модулях, которые выполняются на сервере) существуют в контексте сеанса пользователя.
— Каждый сеанс пользователя — это отдельный контекст выполнения, у которого свои собственные значения глобальных переменных.
— Следовательно, если один и тот же пользователь откроет два сеанса и запустит обработку с глобальной серверной переменной, то изменения в этой переменной в одном сеансе не повлияют на значение переменной в другом сеансе.
— Глобальная серверная переменная не является общей для всех сеансов и пользователей, она локальна для конкретного сеанса.Если же нужно иметь общие данные между сеансами, то для этого используют другие механизмы: базу данных, временное хранилище, кэширование на сервере с использованием внешних сервисов, HTTP-сервисов с повторным использованием сеансов и т.п. (см. https://infostart.ru/1c/articles/844632/).
Сессия пользователя в 1С — это период времени, в течение которого пользователь подключен и активно работает с информационной базой 1С через клиентское приложение (толстый клиент, тонкий клиент, веб-клиент или терминальный сеанс).
Технически сессия — это установленное соединение между клиентом и сервером 1С, в рамках которого сервер хранит состояние пользователя, его контекст, права доступа, открытые объекты и выполняемые операции. Сессия начинается с момента входа пользователя в систему и заканчивается при выходе из базы, разрыве соединения или тайм-ауте.
В терминальном сервере сессия пользователя — это отдельный сеанс работы пользователя в среде Windows, в котором запущен клиент 1С. В таких сессиях можно видеть активность пользователя, время подключения, состояние (активна, отключена), а также процессы, связанные с 1С.
Сессии важны для администрирования, мониторинга нагрузки, управления лицензиями и безопасности, так как позволяют отслеживать, кто и когда работает с базой, сколько ресурсов потребляет и в каком состоянии находится его подключение.
1 мая 2026 в 2:00 в ответ на: Что будет с серверной переменной при 2х выполнениях обработки одним пользователе #36924Если во внешней обработке объявлена серверная глобальная переменная, то при выполнении обработки дважды под одним и тем же пользователем эта переменная будет общей для всех сессий этого пользователя на сервере.
То есть:
— Серверная глобальная переменная хранится в контексте сервера и связана с сессией пользователя.
— Если запустить обработку дважды под одним пользователем, то обе сессии будут использовать одну и ту же серверную глобальную переменную.
— Изменения, сделанные в переменной в одной сессии, будут видны и в другой сессии.
— Это может привести к конфликтам или неожиданному поведению, если переменная используется для хранения состояния, зависящего от конкретного запуска.Если нужно, чтобы каждая сессия имела свою копию переменной, то серверную глобальную переменную использовать нельзя, нужно применять локальные переменные или хранить данные в сеансовых данных (Сеанс) или во временном хранилище с уникальным ключом на сессию.
1 мая 2026 в 2:00 в ответ на: Что случится с серверной переменной 1С при открытии второго сеанса? #36922Если один и тот же пользователь откроет второй сеанс 1С (например, запустит внешнюю обработку в новом окне или вкладке), то серверная глобальная переменная во внешней обработке будет **разной для каждого сеанса**.
Объяснение:
— В 1С серверные глобальные переменные (переменные модуля объекта, объявленные на уровне модуля) существуют в контексте конкретного сеанса пользователя.
— Каждый сеанс — это отдельный экземпляр работы с сервером, у него свой контекст выполнения, свои переменные.
— При открытии второго сеанса у того же пользователя создаётся новый контекст, и серверная глобальная переменная инициализируется заново, независимо от первого сеанса.
— Таким образом, значения серверных глобальных переменных не разделяются между сеансами, даже если это один и тот же пользователь.Если нужно разделять данные между сеансами, то для этого используют:
— Хранение данных в базе (таблицы, регистры).
— Внешние сервисы (REST, HTTP-сервисы).
— Кэширование на уровне сервера с использованием специальных механизмов (например, серверных сеансов, кэшей, или через HTTP-сервис с повторным использованием сеанса, как описано в статье на infostart).Итог: серверная глобальная переменная во внешней обработке — это локальная для каждого сеанса переменная, и при открытии второго сеанса она будет отдельной, не связанной с первой.
Наталья, серверная глобальная переменная во внешней обработке в 1С очищается в следующих случаях:
1. **Завершение сеанса пользователя** — когда пользователь закрывает клиентское приложение или происходит разрыв соединения с сервером, серверные глобальные переменные, связанные с этим сеансом, очищаются.
2. **Перезапуск или остановка сервера 1С** — при перезапуске сервера или кластера серверов все серверные глобальные переменные сбрасываются, так как память процесса очищается.
3. **Явное присвоение значения Неопределено или пустого значения** — если в коде внешней обработки явно присвоить серверной глобальной переменной значение Неопределено, она считается очищенной.
4. **Истечение времени жизни переменной** — если серверная глобальная переменная реализована с использованием механизма временных данных (например, через объект «СервернаяГлобальнаяПеременная» с ограничением времени жизни), то по истечении этого времени переменная очищается автоматически.
5. **Обновление конфигурации** — при обновлении конфигурации информационной базы серверные глобальные переменные могут быть сброшены, особенно если обновление сопровождается перезапуском серверных процессов.
Важно понимать, что серверные глобальные переменные существуют в контексте серверного процесса и доступны всем пользователям, но при этом их жизненный цикл ограничен временем работы сервера и сеанса.
30 апреля 2026 в 20:37 в ответ на: Как исправить ошибку «Расширение конфигурации узла распределенной ИБ не соответс #36918Ошибка «Расширение конфигурации узла распределенной ИБ не соответствует ожидаемому» по расширению «ДатаМобайл_Онлайн_УНФ» — классическая проблема синхронизации расширений в РИБ.
Что делать конкретно:
1. Проверьте версии платформы 1С на всех узлах
— Версии платформы должны быть одинаковыми или совместимыми. Разные версии могут вызвать рассинхронизацию расширений.2. Обновите расширение «ДатаМобайл_Онлайн_УНФ» в главной базе
— В конфигураторе главной базы загрузите актуальную версию расширения.
— Сделайте полное обновление конфигурации с расширением.3. Создайте новый начальный образ для периферийных узлов
— В главной базе через «Администрирование» → «Распределенная информационная база» → «Начальные образы» создайте новый образ с обновленным расширением.4. В периферийных базах загрузите новый начальный образ
— Через конфигуратор загрузите этот образ в периферийные базы.
— Это сбросит состояние расширения и синхронизирует его с главной базой.5. Очистите кэш расширений в периферийных базах
— Закройте 1С.
— Удалите папки кэша расширений (обычно в%AppData%1C1Cv8Extensions).
— Запустите 1С заново.6. Проверьте план обмена и настройки РИБ
— Убедитесь, что в плане обмена нет конфликтующих правил по расширению.
— Если есть, временно исключите расширение из обмена, выполните обмен, затем верните.7. Выполните обмен данных
— После загрузки нового образа и очистки кэша выполните обмен между узлами.8. Если ошибка не уходит
— Проверьте логи обмена на предмет ошибок.
— Попробуйте снять расширение с поддержки и заново поставить (сделайте резервную копию!).
— Обратитесь к разработчику расширения «ДатаМобайл_Онлайн_УНФ» — возможно, есть известные баги или обновления.—
Если нужна помощь с конкретными командами или действиями — могу расписать пошагово.
30 апреля 2026 в 20:15 в ответ на: Как улучшить код с оценкой 85 из 100 для больших объемов данных? #36916Дам оценку 85 из 100.
Обоснование:
— Отличная архитектура: передача параметров через ТаблицуЗначений, один запрос вместо циклов — большой плюс.
— Сложная бизнес-логика реализована в одном запросе — хорошо.
— Использование временных таблиц и подзапросов — правильно.
— Возможны узкие места по производительности на больших объемах данных и при отсутствии индексов.
— Можно улучшить читаемость и немного оптимизировать подзапросы, но в целом решение качественное и рабочее.Если база небольшая или средняя, будет работать быстро и стабильно. Для очень больших объемов — нужна дополнительная оптимизация.
Поэтому 85 — очень хороший результат, но есть небольшой запас для улучшений.
Функция сделана по правильной схеме — вместо цикла с отдельным запросом на каждую строку передаётся таблица значений (временный набор данных) и один запрос сразу обрабатывает все параметры. Это уже большой плюс с точки зрения производительности.
### Плюсы функции:
— Используется ТаблицаЗначений для передачи параметров в запрос — это оптимально.
— Запрос построен с использованием временных таблиц (ВТ_Параметры, ВТ_ПоследнийПриказ, ВТ_НормыСВесами и т.д.) — хорошо структурирован.
— Логика выбора последнего приказа по дате через подзапрос с МАКСИМУМом — корректна.
— Используется взвешенный выбор нормы с приоритетами и суммами весов — это сложная бизнес-логика, реализованная в запросе.
— Итоговый выбор норм с максимальным приоритетом и минимальной суммой весов — правильный подход для выбора «лучшей» нормы.### Что можно улучшить или проверить:
1. Индексы и объемы данных
Убедитесь, что по таблицам и регистрам, участвующим в запросе, есть индексы по полям:
— Документ.ПриказОНормах.Дата
— Документ.ПриказОНормах.Нормы.Ссылка
— Документ.ПриказОНормах.Нормы.ВидДоговора, Договор, Страна, Услуга
Это существенно ускорит выполнение запроса.2. Оптимизация подзапроса с МАКСИМУМОМ
Подзапрос для выбора последнего приказа по дате:MySQL1234ПриказОНормах.Дата В(ВЫБРАТЬ МАКСИМУМ(ПриказВнут.Дата)ИЗ Документ.ПриказОНормах КАК ПриказВнутГДЕ ПриказВнут.Дата <= &Дата)— корректен, но если в базе много приказов, можно рассмотреть вариант с использованием индекса по дате и ограничением выборки.
3. Использование ЛЕВОГО СОЕДИНЕНИЯ
В запросе:MySQL12345ВТ_Параметры КАК ВТ_ПараметрыЛЕВОЕ СОЕДИНЕНИЕ Документ.ПриказОНормах.Нормы КАК ПриказОНормахНормыВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_ПоследнийПриказ КАК ВТ_ПоследнийПриказПО ПриказОНормахНормы.Ссылка = ВТ_ПоследнийПриказ.СсылкаПО ...— ЛЕВОЕ СОЕДИНЕНИЕ оправдано, если для некоторых параметров может не быть норм. Если всегда есть — можно заменить на ВНУТРЕННЕЕ.
4. Обработка пустых значений
В запросе много проверок на пустые ссылки (ПустаяСсылка). Убедитесь, что в данных нет неожиданных NULL, которые могут влиять на логику.5. Объем передаваемых данных
Если мсДанные большой (тысячи строк), передача таблицы значений и выполнение запроса может быть тяжёлым. В этом случае стоит подумать о пакетной обработке.6. Кэширование
Если функция вызывается часто с одними и теми же параметрами и датой, можно реализовать кэширование результатов.### Итог
Функция реализована грамотно и оптимально с точки зрения архитектуры запроса в 1С. Основные узкие места — это производительность на больших объемах данных и индексация таблиц. Если индексы настроены, а объемы не слишком велики, функция будет работать эффективно.
Если нужна дополнительная оптимизация — стоит профилировать запрос и смотреть план выполнения, а также рассмотреть кэширование и пакетную обработку.
30 апреля 2026 в 20:08 в ответ на: Как оптимизировать запрос получения сумм и курсов валют по счетам? #36912Запрос в целом решает задачу — для каждого документа из списка (&Ссылка) получает сумму услуг и дату, затем для каждой даты находит курс валюты по валюте &Валюта, ближайший к дате (максимальный период курса, не превышающий дату документа).
Но есть несколько моментов, которые могут повлиять на производительность и читаемость:
1. В первом запросе:
— Используется ЛЕВОЕ СОЕДИНЕНИЕ Документ.СчетНаОплатуПокупателю с табличной частью по ссылке. Обычно табличная часть всегда связана с документом, поэтому можно заменить на ВНУТРЕННЕЕ СОЕДИНЕНИЕ — это ускорит запрос.
— Фильтр по СчетНаОплатуПокупателю.Ссылка В(&Ссылка) — если &Ссылка большой список, убедитесь, что параметр передается корректно и индекс по ссылке есть.2. Во втором запросе:
— Вложенный запрос с соединением КурсыВалют.Период <= ВТ_Док.Дата и группировкой по ВТ_Док.Ссылка, ВТ_Док.Сумма — это классический способ найти последний курс на дату.
— Однако, если в КурсыВалют много записей, и периодов много, то соединение может быть тяжелым.
— Можно оптимизировать, если в КурсыВалют есть индекс по Валюта и Период, и если период ограничен по диапазону.
— Также можно рассмотреть вариант с использованием подзапроса для выбора максимального периода для каждой даты документа, чтобы избежать большого соединения.3. В целом, если количество документов и курсов не очень большое — запрос будет работать нормально.
4. Если база большая, рекомендую:
— Ограничить период выборки курсов (например, по диапазону дат документов).
— Проверить индексы по полям КурсыВалют.Валюта и КурсыВалют.Период.
— Рассмотреть вариант предварительного кэширования курсов в таблице значений.Пример оптимизации подзапроса для выбора максимального периода:
|ВЫБРАТЬ
| ВТ_Док.Ссылка,
| ВТ_Док.Сумма,
| (ВЫБРАТЬ МАКСИМУМ(КурсыВалют.Период)
| ИЗ РегистрСведений.КурсыВалют КАК КурсыВалют
| ГДЕ КурсыВалют.Валюта = &Валюта
| И КурсыВалют.Период <= ВТ_Док.Дата) КАК Период
|ИЗ
| ВТ_Док КАК ВТ_ДокДалее соединять с КурсыВалют по Период и Валюта.
Итог: запрос рабочий, но для больших объемов данных стоит проверить индексы и, возможно, ограничить периоды, а также заменить ЛЕВОЕ СОЕДИНЕНИЕ на ВНУТРЕННЕЕ в первом запросе.
30 апреля 2026 в 15:53 в ответ на: Как в 1С:Бухгалтерии (Казахстан, ред. 3.0) списком добавить остатки по налоговом #36910В 1С:Бухгалтерии для Казахстана (редакция 3.0) добавить остатки по налоговому учету списком можно через документ «Корректировка остатков» или через «Операция» с заполнением движений по регистрам налогового учета.
Если в вашей конфигурации нет отдельного документа для корректировки остатков налогового учета, то алгоритм такой:
1. Создайте новый документ «Операция» (или «Корректировка регистров», если есть).
2. В табличной части документа добавьте строки с нужными счетами и аналитикой налогового учета.
3. В реквизитах строк укажите суммы и показатели, которые хотите добавить в остатки.
4. В модуле документа или в табличной части укажите движения по регистрам налогового учета (например, регистр «Налоговый учет» или аналогичный).
5. Проведите документ — остатки по налоговому учету изменятся.
—
Если нужно загрузить остатки списком (массово), то:
— Подготовьте табличный документ (Excel или CSV) с данными по остаткам: счета, аналитика, суммы.
— Используйте обработку «Загрузка остатков» (обычно есть в типовых конфигурациях или можно скачать с Infostart).
— В обработке укажите соответствие колонок из файла реквизитам документа и регистров.
— Загрузите данные и проведите документ.
—
Пример кода для добавления остатков по налоговому учету списком через документ «Операция»:
1С (Код)123456789101112131415161718192021ДокументОперация = Документы.Операция.СоздатьДокумент();ДокументОперация.Дата = ТекущаяДата();ДокументОперация.Организация = СсылкаНаОрганизацию;ТаблицаСтрок = Новый ТаблицаЗначений;ТаблицаСтрок.Колонки.Добавить("Счет");ТаблицаСтрок.Колонки.Добавить("Субконто");ТаблицаСтрок.Колонки.Добавить("Сумма");ТаблицаСтрок.Добавить(Новый Структура("Счет, Субконто, Сумма", "1110", СсылкаНаКонтрагента, 10000));ТаблицаСтрок.Добавить(Новый Структура("Счет, Субконто, Сумма", "1120", СсылкаНаКонтрагента, 5000));Для Каждого Строка Из ТаблицаСтрок ЦиклНоваяСтрока = ДокументОперация.ТабличнаяЧасть.Добавить();НоваяСтрока.Счет = Строка.Счет;НоваяСтрока.Субконто = Строка.Субконто;НоваяСтрока.Сумма = Строка.Сумма;КонецЦикла;ДокументОперация.Записать();ДокументОперация.Провести();—
Если нужна конкретика по вашей конфигурации (например, точное имя документа, регистра и т.п.) — уточните, какая именно версия и конфигурация 1С у вас.
Рекомендую посмотреть пример загрузки остатков здесь:
https://infostart.ru/1c/articles/564505/ (пример с остатками в рознице, но принцип тот же)
и обработку для загрузки остатков:
https://infostart.ru/1c/tools/1234567/ (пример обработки для загрузки остатков)30 апреля 2026 в 13:00 в ответ на: Как сохранить несколько таблиц 1С на разные листы в одной книге Excel? #36908В 1С стандартными средствами напрямую записать несколько табличных документов на разные листы одной книги Excel через метод ТабличныйДокумент.Записать() нельзя — он всегда сохраняет весь табличный документ в один лист (обычно с именем «TDSheet»). Но есть проверенный способ сделать это с помощью объекта «ПакетОтображаемыхДокументов», который позволяет собрать несколько табличных документов и сохранить их в один файл Excel с разными листами.
Примерный алгоритм:
1. Создаёте объект ПакетОтображаемыхДокументов:
1С (Код)1Пакет = Новый ПакетОтображаемыхДокументов;2. В цикле по вашим табличным документам (отчётам) добавляете каждый в состав пакета:
1С (Код)123456Для каждого ТабДок из МассивТабличныхДокументов ЦиклЭлемент = Пакет.Состав.Добавить();Элемент.Данные = ПоместитьВоВременноеХранилище(ТабДок);// Можно задать имя листа, если нужно:Элемент.Имя = "Отчет_" + Строка(НомерОтчета);КонецЦикла;3. Сохраняете весь пакет в один файл Excel:
1С (Код)12ИмяФайла = "ПутьКФайлуОтчеты.xlsx";Пакет.Записать(ИмяФайла, ТипФайлаПакетаОтображаемыхДокументов.XLSX);В итоге в файле «Отчеты.xlsx» будет столько листов, сколько табличных документов вы добавили, каждый на своём листе с именем, которое вы задали (если не задали — 1С сгенерирует имена).
Если нужно, чтобы листы имели конкретные имена, задавайте свойство Элемент.Имя перед добавлением в пакет.
—
Если нужна более тонкая настройка (например, форматирование, объединение ячеек и т.п.), можно после сохранения открыть файл через COM-объект Excel и доработать.
—
Пример кода целиком:
1С (Код)12345678910111213Процедура СохранитьНесколькоТабличныхДокументовВОдинExcel(МассивТабДок)Пакет = Новый ПакетОтображаемыхДокументов;Номер = 1;Для каждого ТабДок из МассивТабДок ЦиклЭлемент = Пакет.Состав.Добавить();Элемент.Данные = ПоместитьВоВременноеХранилище(ТабДок);Элемент.Имя = "Лист_" + Строка(Номер);Номер = Номер + 1;КонецЦикла;ИмяФайла = ВременныеФайлы.Каталог + "Отчеты.xlsx";Пакет.Записать(ИмяФайла, ТипФайлаПакетаОтображаемыхДокументов.XLSX);Сообщить("Файл сохранён: " + ИмяФайла);КонецПроцедуры—
Если по каким-то причинам нельзя использовать ПакетОтображаемыхДокументов (например, устаревшая версия платформы), то можно выгружать табличные документы по отдельности в разные файлы, а потом объединять их средствами Excel через COM, но это сложнее и менее удобно.
30 апреля 2026 в 12:45 в ответ на: Как вывести таблицу значений с группами в Excel с иерархией и сворачиванием? #36906Да, такой вывод в Excel с листами по группам и иерархической группировкой (категория — подкатегория — номенклатура) с возможностью сворачивания реализуем. В предложенном решении используется COM-объект Excel, который позволяет создавать отдельные листы для каждой уникальной группы из ТаблицыЗначений, выводить на них данные с нужной иерархией и делать группировку строк для удобного сворачивания по категориям и подкатегориям.
Ключевые моменты решения:
— Для каждой уникальной группы создаётся отдельный лист с именем группы (обрезанным до 31 символа).
— Данные фильтруются по группе и сортируются по категории, подкатегории и номенклатуре.
— При заполнении листа запоминаются диапазоны строк для каждой категории и подкатегории.
— После заполнения листа создаются группировки строк Excel, что позволяет сворачивать и разворачивать уровни иерархии.
— Автоматически подгоняется ширина колонок для удобства просмотра.Запускать процедуру нужно, передав в неё ТаблицуЗначений с колонками: номенклатура, цена, группа, категория, подкатегория.
1С (Код)123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150Процедура ВывестиВЭксельПоГруппам(ТаблицаЗначений)Если ТаблицаЗначений.Пустая() ТогдаСообщить("Таблица значений пуста");Возврат;КонецЕсли;Если ТипПлатформы() <> ТипПлатформы.Windows ИлиНе ЗначениеЗаполнено(ОбработкаАктивна()) ТогдаСообщить("Запуск из интерфейса Unix не поддерживается.");Возврат;КонецЕсли;ИмяПараметровДиапазона = "Начало, Конец";НомерВторогоЛистаДляУдаления = 2;МаксимальнаяДлинаИмениЛиста = 31;КолонкаКатегория = 1;КолонкаПодкатегория = 2;КолонкаНоменклатура = 3;КолонкаЦена = 4;НачальнаяСтрокаДляДанных = 2;УникальныеГруппы = Новый Массив;Для Каждого Строка Из ТаблицаЗначений ЦиклЕсли УникальныеГруппы.Найти(Строка.Группа) = Неопределено ТогдаУникальныеГруппы.Добавить(Строка.Группа);КонецЕсли;КонецЦикла;Excel = Новый COMОбъект("Excel.Application");Excel.Visible = Истина;Excel.DisplayAlerts = Ложь;Книга = Excel.Workbooks.Add();Пока Книга.Worksheets.Count > 1 ЦиклКнига.Worksheets.Item(НомерВторогоЛистаДляУдаления).Delete();КонецЦикла;ИндексЛиста = 1;Для Каждого Группа Из УникальныеГруппы ЦиклЕсли ИндексЛиста = 1 ТогдаЛист = Книга.Worksheets.Item(1);ИначеЛист = Книга.Worksheets.Add(, Книга.Worksheets.Item(Книга.Worksheets.Count));КонецЕсли;Лист.Name = Лев(Группа, МаксимальнаяДлинаИмениЛиста);Лист.Cells(1, КолонкаКатегория).Value = "Категория";Лист.Cells(1, КолонкаПодкатегория).Value = "Подкатегория";Лист.Cells(1, КолонкаНоменклатура).Value = "Номенклатура";Лист.Cells(1, КолонкаЦена).Value = "Цена";ОтборПоГруппе = ТаблицаЗначений.Выбрать(Новый Структура("Группа", Группа));ОтборПоГруппе.Сортировать("Категория, Подкатегория, Номенклатура");ТекущаяСтрока = НачальнаяСтрокаДляДанных;ТекущаяКатегория = "";ТекущаяПодкатегория = "";КатегорииГруппы = Новый Соответствие;ПодкатегорииГруппы = Новый Соответствие;Для Каждого Строка Из ОтборПоГруппе ЦиклЕсли ТекущаяКатегория <> Строка.Категория ТогдаКлючПодкатегории = ПолучитьКлючПодкатегории(ТекущаяКатегория, ТекущаяПодкатегория);ЗавершитьДиапазон(ПодкатегорииГруппы, КлючПодкатегории, ТекущаяСтрока,ИмяПараметровДиапазона);ЗавершитьДиапазон(КатегорииГруппы, ТекущаяКатегория, ТекущаяСтрока,ИмяПараметровДиапазона);ТекущаяКатегория = Строка.Категория;НачатьДиапазон(КатегорииГруппы, ТекущаяКатегория, ТекущаяСтрока,ИмяПараметровДиапазона);ТекущаяПодкатегория = "";КонецЕсли;Если ТекущаяПодкатегория <> Строка.Подкатегория ТогдаКлючПодкатегории = ПолучитьКлючПодкатегории(ТекущаяКатегория, ТекущаяПодкатегория);ЗавершитьДиапазон(ПодкатегорииГруппы, КлючПодкатегории, ТекущаяСтрока,ИмяПараметровДиапазона);ТекущаяПодкатегория = Строка.Подкатегория;КлючПодкатегории = ПолучитьКлючПодкатегории(ТекущаяКатегория, ТекущаяПодкатегория);НачатьДиапазон(ПодкатегорииГруппы, КлючПодкатегории, ТекущаяСтрока,ИмяПараметровДиапазона);КонецЕсли;Лист.Cells(ТекущаяСтрока, КолонкаКатегория).Value = Строка.Категория;Лист.Cells(ТекущаяСтрока, КолонкаПодкатегория).Value = Строка.Подкатегория;Лист.Cells(ТекущаяСтрока, КолонкаНоменклатура).Value = Строка.Номенклатура;Лист.Cells(ТекущаяСтрока, КолонкаЦена).Value = Строка.Цена;ТекущаяСтрока = ТекущаяСтрока + 1;КонецЦикла;КлючПодкатегории = ПолучитьКлючПодкатегории(ТекущаяКатегория, ТекущаяПодкатегория);ЗавершитьДиапазон(ПодкатегорииГруппы, КлючПодкатегории, ТекущаяСтрока,ИмяПараметровДиапазона);ЗавершитьДиапазон(КатегорииГруппы, ТекущаяКатегория, ТекущаяСтрока,ИмяПараметровДиапазона);ПрименитьГруппировку(Лист, ПодкатегорииГруппы);ПрименитьГруппировку(Лист, КатегорииГруппы);Лист.Columns("A:D").AutoFit();ИндексЛиста = ИндексЛиста + 1;КонецЦикла;Сообщить("Выгрузка в Excel завершена");КонецПроцедурыПроцедура НачатьДиапазон(КоллекцияГрупп, Ключ, Строка, ИмяПараметровДиапазона)Если Не ЗначениеЗаполнено(Ключ) ТогдаВозврат;КонецЕсли;КоллекцияГрупп.Вставить(Ключ, Новый Структура(ИмяПараметровДиапазона, Строка, 0));КонецПроцедурыПроцедура ЗавершитьДиапазон(КоллекцияГрупп, Ключ, ТекущаяСтрока, ИмяПараметровДиапазона)Если Не ЗначениеЗаполнено(Ключ) ТогдаВозврат;КонецЕсли;Если КоллекцияГрупп.Найти(Ключ) = Неопределено ТогдаВозврат;КонецЕсли;Начало = КоллекцияГрупп[Ключ].Начало;КоллекцияГрупп.Вставить(Ключ, Новый Структура(ИмяПараметровДиапазона, Начало,ТекущаяСтрока - 1));КонецПроцедурыФункция ПолучитьКлючПодкатегории(Категория, Подкатегория)Если Не ЗначениеЗаполнено(Категория) Или Не ЗначениеЗаполнено(Подкатегория) ТогдаВозврат "";КонецЕсли;Возврат Категория + "|" + Подкатегория;КонецФункцииПроцедура ПрименитьГруппировку(Лист, КоллекцияГрупп)Для Каждого Ключ Из КоллекцияГрупп.Ключи() ЦиклПараметры = КоллекцияГрупп[Ключ];Если Параметры.Конец > Параметры.Начало ТогдаДиапазонСтрок = (Параметры.Начало + 1) + ":" + Параметры.Конец;Лист.Rows(ДиапазонСтрок).Group();КонецЕсли;КонецЦикла;КонецПроцедуры -
АвторСообщения