Ответы в темах
-
АвторСообщения
-
27 апреля 2026 в 14:21 в ответ на: Как вставить номер заказа клиента в форму накладной из реализации товаров? #36834
Чтобы вставить номер заказа клиента в печатную форму Расходной накладной, которая печатается из документа РеализацияТоваровУслуг, нужно сделать следующее:
1. Проверить, что в документе РеализацияТоваровУслуг есть ссылка на ЗаказКлиента
В типовой конфигурации в документе РеализацияТоваровУслуг есть реквизит ЗаказКлиента (ссылка на документ ЗаказКлиента). Если его нет — нужно добавить.
2. Открыть макет печатной формы Расходной накладной
— В конфигураторе откройте объект «Документ.РеализацияТоваровУслуг».
— Перейдите в раздел «Макеты печатных форм».
— Найдите макет Расходной накладной (обычно называется «РасходнаяНакладная» или похожим именем).
— Откройте макет в редакторе (FastReport или встроенный редактор).3. Добавить поле для номера заказа клиента
— В нужном месте макета (например, в шапке документа или рядом с реквизитами документа) добавьте текстовое поле.
— В качестве выражения для этого поля укажите:1С (Код)1[Документ.ЗаказКлиента.Номер]Если макет на FastReport, то выражение будет примерно такое:
1С (Код)1[Документ.ЗаказКлиента.Номер]4. Если в макете нет объекта «Документ.ЗаказКлиента» — нужно расширить выборку данных
В макете печатной формы данные берутся из объекта, который формируется в коде печатной формы.
— В модуле менеджера документа РеализацияТоваровУслуг найдите процедуру, которая формирует печатную форму (например,
СформироватьПечатнуюФормуРасходнойНакладной).
— В этой процедуре нужно добавить передачу реквизита ЗаказКлиента в макет.Пример (в модуле менеджера расширения):
|&Вместо(«СформироватьПечатнуюФормуРасходнойНакладной»)
|Функция СформироватьПечатнуюФормуРасходнойНакладной(Параметры)
| ИсходнаяФорма = ЭтотОбъект.СформироватьПечатнуюФормуРасходнойНакладной(Параметры);
| ИсходнаяФорма.ОбластьДанных.Параметры.ЗаказКлиента = ЭтотОбъект.ЗаказКлиента;
| Возврат ИсходнаяФорма;
|КонецФункции5. В макете добавить параметр «ЗаказКлиента»
— В редакторе макета добавьте параметр «ЗаказКлиента» типа «ДокументСсылка.ЗаказКлиента».
— В поле для номера заказа укажите выражение:1С (Код)1[ЗаказКлиента.Номер]6. Проверить и протестировать
— Сохраните изменения.
— Запустите 1С в режиме предприятия.
— Откройте документ РеализацияТоваровУслуг, у которого заполнен реквизит ЗаказКлиента.
— Распечатайте Расходную накладную.
— Убедитесь, что номер заказа клиента отображается.—
Если хотите сделать через расширение конфигурации, то:
— Создайте расширение.
— В модуле менеджера документа РеализацияТоваровУслуг сделайте перехват функции формирования печатной формы.
— Добавьте передачу реквизита ЗаказКлиента в макет.
— В макете расширения добавьте поле с номером заказа.—
Рекомендую посмотреть подробный пример по добавлению реквизита в печатную форму здесь:
https://infostart.ru/public/1590240/Там подробно описан процесс добавления своего реквизита в макет печатной формы.
27 апреля 2026 в 14:06 в ответ на: Как найти и исправить расхождения между удержанным и исчисленным налогом в 1С:БП #36832Ошибка «Расхождение между удержанным и исчисленным налогом по следующим справкам» в 1С:Бухгалтерия предприятия 8 обычно связана с несоответствием данных в справках 2-НДФЛ или 6-НДФЛ, а именно — суммы удержанного налога не совпадают с суммами исчисленного налога по документам.
Как найти и исправить эту ошибку:
1. Проверка документов, формирующих налоговые справки:
— Откройте раздел «Зарплата и кадры» → «Налоги и взносы» → «Справки 2-НДФЛ» или «Справки 6-НДФЛ».
— Посмотрите список справок, по которым возникает расхождение.
— Откройте проблемные справки и проверьте суммы исчисленного и удержанного налога.2. Анализ документов начисления и удержания налога:
— Проверьте документы начисления зарплаты, где рассчитывается налог (например, «Начисление зарплаты»).
— Проверьте документы удержания налога (например, «Удержание НДФЛ»).
— Убедитесь, что суммы в этих документах соответствуют суммам в справках.3. Используйте стандартные отчеты для поиска расхождений:
— В разделе «Отчеты» → «Налоги и взносы» есть отчет «Свод по НДФЛ» или «Анализ удержанного и исчисленного налога».
— Запустите отчет за нужный период, сравните суммы исчисленного и удержанного налога.
— Отчет покажет, по каким сотрудникам или документам есть расхождения.4. Проверка корректности заполнения реквизитов в документах:
— Часто ошибка возникает из-за неправильного заполнения реквизитов «Дата удержания», «Дата перечисления налога», «Сумма налога» в документах.
— Проверьте, что даты удержания и перечисления налога не выходят за пределы отчетного периода.
— Проверьте, что суммы налога не отрицательные и корректно отражены.5. Проверка корректности отражения налогов в регистре налогового учета:
— В конфигураторе или через запросы проверьте регистры налогового учета по НДФЛ.
— Например, запросом можно получить данные по начисленному и удержанному налогу по сотрудникам.Пример запроса для поиска расхождений (адаптируйте под вашу конфигурацию):
|ВЫБРАТЬ
| Начисления.Сотрудник,
| Начисления.Период,
| СУММА(Начисления.НДФЛ_Исчислено) КАК Исчислено,
| СУММА(Удержания.НДФЛ_Удержано) КАК Удержано,
| (СУММА(Начисления.НДФЛ_Исчислено) — СУММА(Удержания.НДФЛ_Удержано)) КАК Разница
|ИЗ
| РегистрНакопления.НДФЛНачислено КАК Начисления
| ЛЕВОЕ СОЕДИНЕНИЕ
| РегистрНакопления.НДФЛУдержано КАК Удержания
| ПО Начисления.Сотрудник = Удержания.Сотрудник
| И Начисления.Период = Удержания.Период
|ГРУППИРОВАТЬ ПО
| Начисления.Сотрудник,
| Начисления.Период
|ИМЕЮЩИЙ
| Разница <> 06. Проверка корректности заполнения справок 2-НДФЛ и 6-НДФЛ:
— Иногда ошибка возникает из-за ручных правок в справках.
— Пересоздайте справки заново, используя стандартные обработки.7. Проверка обновлений конфигурации:
— Убедитесь, что у вас установлена последняя версия конфигурации 1С:Бухгалтерия предприятия.
— В новых релизах часто исправляют ошибки по налогам.8. Исправление ошибок:
— Если нашли документы с неправильными суммами, исправьте их (отмените и создайте заново).
— Если ошибка в датах, скорректируйте даты удержания и перечисления.
— Перепроведите документы.Если после всех проверок ошибка сохраняется, можно использовать стандартную обработку «Проверка корректности данных» в разделе «Администрирование» → «Проверка данных» для выявления проблем.
Рекомендую посмотреть здесь:
https://infostart.ru/public/115832/ — статьи и обсуждения по ошибкам в налоговых справках в 1С БП 8.3https://infostart.ru/public/162776/ — особенности расчета налогов и возможные ошибки.
Это позволит быстро локализовать источник расхождения и исправить его.
27 апреля 2026 в 13:45 в ответ на: Как получить задолженность поставщика через регистр хозрасчетный в 1С? #36830Чтобы посмотреть задолженность поставщика через регистр бухгалтерии «Хозрасчетный» в 1С, нужно сделать запрос к регистру остатков и оборотов по счету расчетов с поставщиками. Обычно задолженность поставщика отражается на счете расчетов с поставщиками (например, 60 счет в плане счетов).
Пример запроса на языке 1С для получения задолженности поставщика по счету расчетов с поставщиками через регистр бухгалтерии «Хозрасчетный.ОстаткиИОбороты»:
1С (Код)12345678910111213141516171819202122Запрос = Новый Запрос;Запрос.Текст ="ВЫБРАТЬ| ХозрасчетныйОстатки.Контрагент КАК Поставщик,| СУММА(ХозрасчетныйОстатки.СуммаКонечныйОстатокДт - ХозрасчетныйОстатки.СуммаКонечныйОстатокКт) КАК Задолженность|ИЗ| РегистрБухгалтерии.Хозрасчетный.ОстаткиИОбороты(&ДатаНач, &ДатаКон, Контрагент, , Счет = &Счет) КАК ХозрасчетныйОстатки|ГДЕ| ХозрасчетныйОстатки.Контрагент = &Поставщик|СГРУППИРОВАТЬ ПО| ХозрасчетныйОстатки.Контрагент";Запрос.УстановитьПараметр("ДатаНач", НачалоДня(Дата));Запрос.УстановитьПараметр("ДатаКон", КонецДня(Дата));Запрос.УстановитьПараметр("Поставщик", Справочники.Контрагенты.НайтиПоНаименованию("ИмяПоставщика"));Запрос.УстановитьПараметр("Счет", ПланыСчетов.Хозрасчетный.РасчетыСПоставщиками);Результат = Запрос.Выполнить();Выборка = Результат.Выбрать();Пока Выборка.Следующий() ЦиклСообщить("Поставщик: " + Выборка.Поставщик + ", Задолженность: " + Формат(Выборка.Задолженность, "ЧГ=10; ЧД=2"));КонецЦикла;Объяснение:
— В запросе выбирается контрагент (поставщик) и рассчитывается задолженность как разница между дебетовыми и кредитовыми остатками по счету расчетов с поставщиками.
— ПараметрыДатаНачиДатаКонзадают период, на который берутся остатки.
— ПараметрСчетуказывает на счет расчетов с поставщиками в плане счетов.
— ПараметрПоставщик— конкретный контрагент, по которому нужно посмотреть задолженность.Если нужно получить задолженность по всем поставщикам, уберите условие по контрагенту и группировку по нему.
Также можно смотреть задолженность в стандартных отчетах конфигурации, например, «Состояние расчетов с поставщиками», но через регистр «Хозрасчетный» именно так.
Если нужна помощь с конкретным кодом под вашу конфигурацию — уточните версию 1С и используемый план счетов.
27 апреля 2026 в 11:43 в ответ на: Как исправить ошибку «Переменная не определена (РеализацияТоваровУслуг)»? #36828Ошибка «Переменная не определена (РеализацияТоваровУслуг)» означает, что в контексте выполнения кода переменная или объект с именем РеализацияТоваровУслуг не объявлен и не доступен.
Скорее всего, вы пытаетесь обратиться к реквизитам или свойствам объекта документа или табличной части, но переменная с таким именем не создана.
Как исправить:
1. Проверьте, что переменная РеализацияТоваровУслуг объявлена и содержит ссылку на объект или структуру с нужными данными.
Например, если вы работаете с табличной частью документа РеализацияТоваровУслуг, то обычно перебираете строки так:
|Для каждого СтрокаТЧ Из Объект.Товары Цикл
| НомерЗаказа = СтрокаТЧ.ЗаказКлиента.Номер + » » + Формат(СтрокаТЧ.ЗаказКлиента.Дата, «ДФ=dd.MM.yyyy»);
|КонецЦикла;2. Если вы хотите получить данные из документа РеализацияТоваровУслуг, то сначала получите ссылку на объект документа:
|РеализацияТоваровУслуг = Документы.РеализацияТоваровУслуг.НайтиПоНомеру(«номер», Дата);
|Если НЕ РеализацияТоваровУслуг.Пустая() Тогда
| ОбъектРеализации = РеализацияТоваровУслуг.ПолучитьОбъект();
| НомерЗаказа = ОбъектРеализации.ЗаказКлиента.Номер + » » + Формат(ОбъектРеализации.ЗаказКлиента.Дата, «ДФ=dd.MM.yyyy»);
|КонецЕсли;3. Если вы используете запрос, то в тексте запроса нужно использовать алиас таблицы, например:
|ВЫБРАТЬ
| Реализация.ЗаказКлиента.Номер КАК НомерЗаказа,
| Реализация.ЗаказКлиента.Дата КАК ДатаЗаказа
|ИЗ
| Документ.РеализацияТоваровУслуг КАК Реализация
|ГДЕ
| Реализация.Ссылка = &Ссылка4. В вашем коде ошибка в том, что вы обращаетесь к РеализацияТоваровУслуг как к переменной, но она не объявлена. Нужно либо объявить и присвоить ей значение, либо заменить на правильный объект.
5. Также в вашем коде есть странный фрагмент: Строка(<<?>>РеализацияТоваровУслуг.ЗаказКлиента.Дата);
Вместо этого используйте:
|Формат(РеализацияТоваровУслуг.ЗаказКлиента.Дата, «ДФ=dd.MM.yyyy»)
Или если нужно строковое представление:
|Строка(РеализацияТоваровУслуг.ЗаказКлиента.Дата)
6. Если вы в обработчике формы, то можно получить текущий объект документа через ЭтаФорма.Объект:
|НомерЗаказа = ЭтаФорма.Объект.ЗаказКлиента.Номер + » » + Формат(ЭтаФорма.Объект.ЗаказКлиента.Дата, «ДФ=dd.MM.yyyy»);
Итог: Объявите переменную РеализацияТоваровУслуг и присвойте ей объект документа или строки табличной части, либо замените на правильный объект, с которого хотите получить реквизиты ЗаказКлиента.Номер и Дата.
Если нужен пример, как получить номер и дату заказа из документа РеализацияТоваровУслуг:
|Реализация = Документы.РеализацияТоваровУслуг.НайтиПоНомеру(«000000001», ТекущаяДата());
|Если НЕ Реализация.Пустая() Тогда
| ОбъектРеализации = Реализация.ПолучитьОбъект();
| НомерЗаказа = ОбъектРеализации.ЗаказКлиента.Номер + » » + Формат(ОбъектРеализации.ЗаказКлиента.Дата, «ДФ=dd.MM.yyyy»);
|КонецЕсли;Рекомендую посмотреть здесь:
https://infostart.ru/public/1896407/
https://infostart.ru/public/194765/1С — это платформа и экосистема программных продуктов для автоматизации бизнеса и управления предприятием. Основная цель 1С — помочь компаниям вести учет, управлять процессами и анализировать данные.
Что такое 1С конкретно:
1. Платформа 1С:Предприятие — это среда разработки и исполнения бизнес-приложений. На ней создаются конфигурации (программы) для разных задач: бухгалтерия, торговля, склад, производство, CRM и др.
2. Конфигурации 1С — готовые или кастомные решения, которые автоматизируют конкретные бизнес-процессы. Например, «1С:Бухгалтерия», «1С:Управление торговлей», «1С:Зарплата и кадры».
3. Встроенный язык программирования 1С — позволяет дорабатывать и настраивать конфигурации под нужды конкретной компании.
Зачем 1С нужен вам:
— Автоматизация учета и отчетности — 1С помогает вести бухгалтерский, налоговый, складской, торговый и кадровый учет в соответствии с законодательством.
— Управление бизнес-процессами — планирование закупок, продаж, производства, контроль остатков и финансов.
— Сокращение ошибок и времени на рутину — автоматизация снижает ручной труд и ошибки при вводе данных.
— Аналитика и контроль — удобные отчеты и аналитика для принятия управленческих решений.
— Интеграция с другими системами — 1С может обмениваться данными с банками, интернет-магазинами, веб-сервисами и др.
— Масштабируемость — подходит как для малого бизнеса, так и для крупных предприятий.
Если у вас есть бизнес, где нужно вести учет, контролировать процессы и получать отчеты — 1С будет полезен. Даже если вы не бухгалтер или ИТ-специалист, 1С позволяет организовать работу компании эффективнее.
Рекомендую посмотреть здесь для более подробного понимания:
https://helpf.pro/faq/view/1187.htmlВот как можно объединить этот код в единый запрос для отчёта на СКД, используя временную таблицу для хранения оборотов с нужной логикой по периоду и регистратору:
|ВЫБРАТЬ
| ВЫБОР
| КОГДА ХозрасчетныйОбороты.Период < &ДатаНачала
| ТОГДА &ДатаНачала
| ИНАЧЕ ХозрасчетныйОбороты.Период
| КОНЕЦ КАК Период,
| ВЫБОР
| КОГДА ХозрасчетныйОбороты.Период < &ДатаНачала
| ТОГДА NULL
| ИНАЧЕ ХозрасчетныйОбороты.Регистратор
| КОНЕЦ КАК Регистратор,
| ЕСТЬNULL(ХозрасчетныйОбороты.Регистратор.Договор, «Без договора») КАК Договор,
| ХозрасчетныйОбороты.Субконто1 КАК Субконто1,
| ХозрасчетныйОбороты.Субконто2 КАК Субконто2,
| ХозрасчетныйОбороты.Организация КАК Организация,
| ХозрасчетныйОбороты.СуммаОборотДт КАК СуммаОборотДт,
| ХозрасчетныйОбороты.СуммаОборотКт КАК СуммаОборотКт,
| ХозрасчетныйОбороты.КоличествоОборотДт КАК КоличествоОборотДт,
| ХозрасчетныйОбороты.КоличествоОборотКт КАК КоличествоОборотКт
|ПОМЕСТИТЬ ВТ_Обороты
|ИЗ
| РегистрБухгалтерии.Хозрасчетный.Обороты(
| ,
| &ДатаОкончания,
| Регистратор,
| Счет В ИЕРАРХИИ (&Счет),
| ,
| {(Организация = &Организация), (Подразделение = &Подразделение), (Субконто1 = &Субконто1), (Субконто2 = &Субконто2)},
| ,
| ) КАК ХозрасчетныйОбороты
|
|ИНДЕКСИРОВАТЬ ПО
| Период,
| Субконто1,
| Субконто2,
| Организация;
|
|////////////////////////////////////////////////////////////////////////////////
|
|ВЫБРАТЬ
| *
|ИЗ
| ВТ_Обороты
|ГДЕ
| (Период >= &ДатаНачала)
|УПОРЯДОЧИТЬ ПО
| Период,
| Регистратор,
| Договор,
| Субконто1,
| Субконто2,
| ОрганизацияОбъяснение:
— Сначала создаём временную таблицу ВТ_Обороты с нужными данными и корректируем период и регистратор в зависимости от даты начала.
— Затем из ВТ_Обороты выбираем записи, где период >= &ДатаНачала (то есть только нужный период).
— Индексация и упорядочивание для оптимизации и удобства.Такой подход позволяет использовать данные с корректировкой по периоду и регистратору в одном запросе для отчёта на СКД.
25 апреля 2026 в 0:03 в ответ на: Как исправить ошибку PostgreSQL invalid value for parameter «lc_messages»? #36821Ошибка PostgreSQL:
1С (Код)12ERROR: invalid value for parameter "lc_messages": "en_US.UTF-8"STATEMENT: SET lc_messages to 'en_US.UTF-8';означает, что в вашей системе отсутствует локаль
en_US.UTF-8, или она не поддерживается сервером PostgreSQL.Что делать:
1. Проверьте, какие локали установлены в ОС (Linux):
Shell1locale -aЕсли
en_US.UTF-8нет в списке, значит локаль не установлена.2. Установите локаль
en_US.UTF-8в системе.Для Debian/Ubuntu:
Shell12sudo locale-gen en_US.UTF-8sudo dpkg-reconfigure localesДля CentOS/RHEL:
Shell1localedef -i en_US -f UTF-8 en_US.UTF-83. Перезапустите PostgreSQL после установки локали:
Shell1sudo systemctl restart postgresql4. Проверьте, что локаль появилась:
Shell1locale -a | grep en_US.UTF-85. Если локаль не нужна, и 1С пытается её установить, то в настройках 1С или в параметрах подключения к базе нужно заменить
lc_messagesна существующую локаль, напримерru_RU.UTF-8.6. Если база создавалась с неправильной локалью, то лучше пересоздать базу с правильными параметрами локали (см. ниже).
—
Если проблема связана с созданием базы 1С в PostgreSQL, и локаль не совпадает с локалью кластера, то:
— Инициализируйте кластер PostgreSQL с нужной локалью:
Shell1initdb --locale=ru_RU.UTF-8 --encoding=UTF8 -D /путь/к/кластеру— Или замените шаблон базы
template1на базу с нужной локалью:MySQL1234UPDATE pg_database SET datistemplate = false WHERE datname = 'template1';DROP DATABASE template1;CREATE DATABASE template1 WITH TEMPLATE = template0 ENCODING = 'UTF8' LC_COLLATE = 'ru_RU.UTF-8' LC_CTYPE = 'ru_RU.UTF-8';UPDATE pg_database SET datistemplate = true WHERE datname = 'template1';— После этого создавайте базы 1С через панель администрирования, чтобы они наследовали правильные локали.
—
Рекомендую посмотреть здесь, там подробно про локали и ошибки PostgreSQL с 1С:
Ошибка type mvarchar does not exist при создании базы 1С в PostgreSQL
24 апреля 2026 в 19:18 в ответ на: Как использовать метод Итог() для оптимизации функции распределения? #36819Вот переделанный вариант функции с использованием метода Итог() для подсчёта общей суммы по колонкам. Это позволяет убрать вложенные циклы для подсчёта общей суммы и упростить код:
1С (Код)123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116Функция РаспределитьПропорционально(СуммаКРаспределению, ТаблицаБаза, ИмяКолонкиБаза = "Сумма", КоличествоКолонок = 20)Если ТаблицаБаза = Неопределено Или ТаблицаБаза.Количество() = 0 ТогдаВозврат Новый ТаблицаЗначений;КонецЕсли;// Считаем общую сумму по всем колонкам с помощью Итог()ОбщаяСумма = 0;Для НомерКолонки = 1 По КоличествоКолонок ЦиклИмяКолонки = ИмяКолонкиБаза + Формат(НомерКолонки, "ЧГ=");Если ТаблицаБаза.Колонки.Найти(ИмяКолонки) <> Неопределено ТогдаОбщаяСумма = ОбщаяСумма + ТаблицаБаза.Итог(ИмяКолонки);КонецЕсли;КонецЦикла;Если ОбщаяСумма = 0 Тогда// Если сумма базы 0, то возвращаем копию с нулями по всем колонкамРезультат = ТаблицаБаза.Скопировать();Для Каждого Строка Из Результат ЦиклДля НомерКолонки = 1 По КоличествоКолонок ЦиклИмяКолонки = ИмяКолонкиБаза + Формат(НомерКолонки, "ЧГ=");Если Результат.Колонки.Найти(ИмяКолонки) <> Неопределено ТогдаСтрока[ИмяКолонки] = 0;КонецЕсли;КонецЦикла;КонецЦикла;Возврат Результат;КонецЕсли;// Создаем новую таблицу для результата с нужными колонкамиРезультат = Новый ТаблицаЗначений;Результат.Колонки.Добавить("Показатель");Результат.Колонки.Добавить("КодIC");Для НомерКолонки = 1 По КоличествоКолонок ЦиклРезультат.Колонки.Добавить(ИмяКолонкиБаза + Формат(НомерКолонки, "ЧГ="), Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(15, 2)));КонецЦикла;// Найдем индекс строки с максимальной общей суммой по колонкам (для компенсации погрешности)МаксимальноеЗначение = -1;ИндексМаксимума = 0;Для НомерСтроки = 0 По ТаблицаБаза.Количество() - 1 ЦиклСтрока = ТаблицаБаза[НомерСтроки];СуммаСтроки = 0;Для НомерКолонки = 1 По КоличествоКолонок ЦиклИмяКолонки = ИмяКолонкиБаза + Формат(НомерКолонки, "ЧГ=");Если ТаблицаБаза.Колонки.Найти(ИмяКолонки) <> Неопределено ТогдаЕсли ЗначениеЗаполнено(Строка[ИмяКолонки]) ТогдаСуммаСтроки = СуммаСтроки + Строка[ИмяКолонки];КонецЕсли;КонецЕсли;КонецЦикла;Если СуммаСтроки > МаксимальноеЗначение ТогдаМаксимальноеЗначение = СуммаСтроки;ИндексМаксимума = НомерСтроки;КонецЕсли;КонецЦикла;// Распределяем сумму пропорционально сумме по колонкам в каждой строкеДля НомерСтроки = 0 По ТаблицаБаза.Количество() - 1 ЦиклСтрока = ТаблицаБаза[НомерСтроки];НоваяСтрока = Результат.Добавить();НоваяСтрока.Показатель = Строка.Показатель;НоваяСтрока.КодIC = Строка.КодIC;// Считаем сумму по колонкам для текущей строкиСуммаСтроки = 0;Для НомерКолонки = 1 По КоличествоКолонок ЦиклИмяКолонки = ИмяКолонкиБаза + Формат(НомерКолонки, "ЧГ=");Если ТаблицаБаза.Колонки.Найти(ИмяКолонки) <> Неопределено ТогдаЕсли ЗначениеЗаполнено(Строка[ИмяКолонки]) ТогдаСуммаСтроки = СуммаСтроки + Строка[ИмяКолонки];КонецЕсли;КонецЕсли;КонецЦикла;// Распределяем пропорционально сумме строкиДля НомерКолонки = 1 По КоличествоКолонок ЦиклИмяКолонки = ИмяКолонкиБаза + Формат(НомерКолонки, "ЧГ=");Если ТаблицаБаза.Колонки.Найти(ИмяКолонки) <> Неопределено ТогдаЕсли ЗначениеЗаполнено(Строка[ИмяКолонки]) ТогдаИсходноеЗначение = Строка[ИмяКолонки];ИначеИсходноеЗначение = 0;КонецЕсли;Если ОбщаяСумма = 0 ТогдаРаспределенноеЗначение = 0;ИначеРаспределенноеЗначение = Окр(СуммаКРаспределению * ИсходноеЗначение / ОбщаяСумма, 2, Истина);КонецЕсли;НоваяСтрока[ИмяКолонки] = РаспределенноеЗначение;КонецЕсли;КонецЦикла;КонецЦикла;// Корректируем погрешность округления по каждой колонке, добавляя разницу в строку с максимальной суммойДля НомерКолонки = 1 По КоличествоКолонок ЦиклИмяКолонки = ИмяКолонкиБаза + Формат(НомерКолонки, "ЧГ=");СуммаКолонки = 0;Для НомерСтроки = 0 По Результат.Количество() - 1 ЦиклЕсли ЗначениеЗаполнено(Результат[НомерСтроки][ИмяКолонки]) ТогдаСуммаКолонки = СуммаКолонки + Результат[НомерСтроки][ИмяКолонки];КонецЕсли;КонецЦикла;Разница = СуммаКРаспределению - СуммаКолонки;Если Разница <> 0 ТогдаЕсли ЗначениеЗаполнено(Результат[ИндексМаксимума][ИмяКолонки]) ТогдаРезультат[ИндексМаксимума][ИмяКолонки] = Результат[ИндексМаксимума][ИмяКолонки] + Разница;ИначеРезультат[ИндексМаксимума][ИмяКолонки] = Разница;КонецЕсли;КонецЕсли;КонецЦикла;Возврат Результат;КонецФункцииТеперь метод Итог() используется для подсчёта общей суммы по каждой колонке, что упрощает и ускоряет подсчёт.
24 апреля 2026 в 19:14 в ответ на: Как оптимизировать функцию с параметрами ИмяКолонки и КоличествоКолонок? #36817Вот оптимизированный вариант функции с параметрами:
— ИмяКолонкиБаза — базовое имя колонки, например, «Сумма»
— КоличествоКолонок — количество колонок, например, 20Функция автоматически формирует имена колонок: «Сумма1», «Сумма2», …, «СуммаN».
1С (Код)123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120Функция РаспределитьПропорционально(СуммаКРаспределению, ТаблицаБаза, ИмяКолонкиБаза = "Сумма", КоличествоКолонок = 20)Если ТаблицаБаза = Неопределено Или ТаблицаБаза.Количество() = 0 ТогдаВозврат Новый ТаблицаЗначений;КонецЕсли;// Считаем общую сумму по всем колонкам и всем строкамОбщаяСумма = 0;Для Каждого Строка Из ТаблицаБаза ЦиклДля НомерКолонки = 1 По КоличествоКолонок ЦиклИмяКолонки = ИмяКолонкиБаза + Формат(НомерКолонки, "ЧГ=");Если ТаблицаБаза.Колонки.Найти(ИмяКолонки) <> Неопределено ТогдаЕсли ЗначениеЗаполнено(Строка[ИмяКолонки]) ТогдаОбщаяСумма = ОбщаяСумма + Строка[ИмяКолонки];КонецЕсли;КонецЕсли;КонецЦикла;КонецЦикла;Если ОбщаяСумма = 0 Тогда// Если сумма базы 0, то возвращаем копию с нулями по всем колонкамРезультат = ТаблицаБаза.Скопировать();Для Каждого Строка Из Результат ЦиклДля НомерКолонки = 1 По КоличествоКолонок ЦиклИмяКолонки = ИмяКолонкиБаза + Формат(НомерКолонки, "ЧГ=");Если Результат.Колонки.Найти(ИмяКолонки) <> Неопределено ТогдаСтрока[ИмяКолонки] = 0;КонецЕсли;КонецЦикла;КонецЦикла;Возврат Результат;КонецЕсли;// Создаем новую таблицу для результата с нужными колонкамиРезультат = Новый ТаблицаЗначений;Результат.Колонки.Добавить("Показатель");Результат.Колонки.Добавить("КодIC");Для НомерКолонки = 1 По КоличествоКолонок ЦиклРезультат.Колонки.Добавить(ИмяКолонкиБаза + Формат(НомерКолонки, "ЧГ="), Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(15, 2)));КонецЦикла;// Найдем индекс строки с максимальной общей суммой по колонкам (для компенсации погрешности)МаксимальноеЗначение = -1;ИндексМаксимума = 0;Для НомерСтроки = 0 По ТаблицаБаза.Количество() - 1 ЦиклСтрока = ТаблицаБаза[НомерСтроки];СуммаСтроки = 0;Для НомерКолонки = 1 По КоличествоКолонок ЦиклИмяКолонки = ИмяКолонкиБаза + Формат(НомерКолонки, "ЧГ=");Если ТаблицаБаза.Колонки.Найти(ИмяКолонки) <> Неопределено ТогдаЕсли ЗначениеЗаполнено(Строка[ИмяКолонки]) ТогдаСуммаСтроки = СуммаСтроки + Строка[ИмяКолонки];КонецЕсли;КонецЕсли;КонецЦикла;Если СуммаСтроки > МаксимальноеЗначение ТогдаМаксимальноеЗначение = СуммаСтроки;ИндексМаксимума = НомерСтроки;КонецЕсли;КонецЦикла;// Распределяем сумму пропорционально сумме по колонкам в каждой строкеДля НомерСтроки = 0 По ТаблицаБаза.Количество() - 1 ЦиклСтрока = ТаблицаБаза[НомерСтроки];НоваяСтрока = Результат.Добавить();НоваяСтрока.Показатель = Строка.Показатель;НоваяСтрока.КодIC = Строка.КодIC;// Считаем сумму по колонкам для текущей строкиСуммаСтроки = 0;Для НомерКолонки = 1 По КоличествоКолонок ЦиклИмяКолонки = ИмяКолонкиБаза + Формат(НомерКолонки, "ЧГ=");Если ТаблицаБаза.Колонки.Найти(ИмяКолонки) <> Неопределено ТогдаЕсли ЗначениеЗаполнено(Строка[ИмяКолонки]) ТогдаСуммаСтроки = СуммаСтроки + Строка[ИмяКолонки];КонецЕсли;КонецЕсли;КонецЦикла;// Распределяем пропорционально сумме строкиДля НомерКолонки = 1 По КоличествоКолонок ЦиклИмяКолонки = ИмяКолонкиБаза + Формат(НомерКолонки, "ЧГ=");Если ТаблицаБаза.Колонки.Найти(ИмяКолонки) <> Неопределено ТогдаЕсли ЗначениеЗаполнено(Строка[ИмяКолонки]) ТогдаИсходноеЗначение = Строка[ИмяКолонки];ИначеИсходноеЗначение = 0;КонецЕсли;Если ОбщаяСумма = 0 ТогдаРаспределенноеЗначение = 0;ИначеРаспределенноеЗначение = Окр(СуммаКРаспределению * ИсходноеЗначение / ОбщаяСумма, 2, Истина);КонецЕсли;НоваяСтрока[ИмяКолонки] = РаспределенноеЗначение;КонецЕсли;КонецЦикла;КонецЦикла;// Корректируем погрешность округления по каждой колонке, добавляя разницу в строку с максимальной суммойДля НомерКолонки = 1 По КоличествоКолонок ЦиклИмяКолонки = ИмяКолонкиБаза + Формат(НомерКолонки, "ЧГ=");СуммаКолонки = 0;Для НомерСтроки = 0 По Результат.Количество() - 1 ЦиклЕсли ЗначениеЗаполнено(Результат[НомерСтроки][ИмяКолонки]) ТогдаСуммаКолонки = СуммаКолонки + Результат[НомерСтроки][ИмяКолонки];КонецЕсли;КонецЦикла;Разница = СуммаКРаспределению - СуммаКолонки;Если Разница <> 0 ТогдаЕсли ЗначениеЗаполнено(Результат[ИндексМаксимума][ИмяКолонки]) ТогдаРезультат[ИндексМаксимума][ИмяКолонки] = Результат[ИндексМаксимума][ИмяКолонки] + Разница;ИначеРезультат[ИндексМаксимума][ИмяКолонки] = Разница;КонецЕсли;КонецЕсли;КонецЦикла;Возврат Результат;КонецФункцииТеперь можно вызвать, например:
1С (Код)1РаспределитьПропорционально(10000, МояТаблица, "Сумма", 20);Или, если колонки называются «СуммаОтгрузки1», «СуммаОтгрузки2» и т.п.:
1С (Код)1РаспределитьПропорционально(5000, МояТаблица, "СуммаОтгрузки", 10);Функция универсальна и легко настраивается под любое количество и базовое имя колонок.
24 апреля 2026 в 18:57 в ответ на: Как безопасно обрабатывать значения в колонках 1С в отсутствии оператора `?()`? #36815Да, в 1С нет оператора «?()» как в других языках. Нужно проверять наличие значения через ПроверитьЗначение() или через условие.
Переделал функцию с учетом этого, чтобы безопасно брать значение из колонки:
1С (Код)123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126Функция РаспределитьПропорционально20(СуммаКРаспределению, ТаблицаБаза)Если ТаблицаБаза = Неопределено Или ТаблицаБаза.Количество() = 0 ТогдаВозврат Новый ТаблицаЗначений;КонецЕсли;// Считаем общую сумму по всем 20 колонкам и всем строкамОбщаяСумма = 0;Для Каждого Строка Из ТаблицаБаза ЦиклДля НомерКолонки = 1 По 20 ЦиклИмяКолонки = "Сумма" + Формат(НомерКолонки, "ЧГ=");Если ТаблицаБаза.Колонки.Найти(ИмяКолонки) <> Неопределено ТогдаЕсли Не ЗначениеЗаполнено(Строка[ИмяКолонки]) ТогдаОбщаяСумма = ОбщаяСумма + 0;ИначеОбщаяСумма = ОбщаяСумма + Строка[ИмяКолонки];КонецЕсли;КонецЕсли;КонецЦикла;КонецЦикла;Если ОбщаяСумма = 0 Тогда// Если сумма базы 0, то возвращаем копию с нулями по всем колонкамРезультат = ТаблицаБаза.Скопировать();Для Каждого Строка Из Результат ЦиклДля НомерКолонки = 1 По 20 ЦиклИмяКолонки = "Сумма" + Формат(НомерКолонки, "ЧГ=");Если Результат.Колонки.Найти(ИмяКолонки) <> Неопределено ТогдаСтрока[ИмяКолонки] = 0;КонецЕсли;КонецЦикла;КонецЦикла;Возврат Результат;КонецЕсли;// Создаем новую таблицу для результата с нужными колонкамиРезультат = Новый ТаблицаЗначений;Результат.Колонки.Добавить("Показатель");Результат.Колонки.Добавить("КодIC");Для НомерКолонки = 1 По 20 ЦиклРезультат.Колонки.Добавить("Сумма" + Формат(НомерКолонки, "ЧГ="), Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(15, 2)));КонецЦикла;// Найдем индекс строки с максимальной общей суммой по 20 колонкам (для компенсации погрешности)МаксимальноеЗначение = -1;ИндексМаксимума = 0;Для НомерСтроки = 0 По ТаблицаБаза.Количество() - 1 ЦиклСтрока = ТаблицаБаза[НомерСтроки];СуммаСтроки = 0;Для НомерКолонки = 1 По 20 ЦиклИмяКолонки = "Сумма" + Формат(НомерКолонки, "ЧГ=");Если ТаблицаБаза.Колонки.Найти(ИмяКолонки) <> Неопределено ТогдаЕсли Не ЗначениеЗаполнено(Строка[ИмяКолонки]) ТогдаСуммаСтроки = СуммаСтроки + 0;ИначеСуммаСтроки = СуммаСтроки + Строка[ИмяКолонки];КонецЕсли;КонецЕсли;КонецЦикла;Если СуммаСтроки > МаксимальноеЗначение ТогдаМаксимальноеЗначение = СуммаСтроки;ИндексМаксимума = НомерСтроки;КонецЕсли;КонецЦикла;// Распределяем сумму пропорционально сумме по 20 колонкам в каждой строкеДля НомерСтроки = 0 По ТаблицаБаза.Количество() - 1 ЦиклСтрока = ТаблицаБаза[НомерСтроки];НоваяСтрока = Результат.Добавить();НоваяСтрока.Показатель = Строка.Показатель;НоваяСтрока.КодIC = Строка.КодIC;// Считаем сумму по 20 колонкам для текущей строкиСуммаСтроки = 0;Для НомерКолонки = 1 По 20 ЦиклИмяКолонки = "Сумма" + Формат(НомерКолонки, "ЧГ=");Если ТаблицаБаза.Колонки.Найти(ИмяКолонки) <> Неопределено ТогдаЕсли Не ЗначениеЗаполнено(Строка[ИмяКолонки]) ТогдаСуммаСтроки = СуммаСтроки + 0;ИначеСуммаСтроки = СуммаСтроки + Строка[ИмяКолонки];КонецЕсли;КонецЕсли;КонецЦикла;// Распределяем пропорционально сумме строкиДля НомерКолонки = 1 По 20 ЦиклИмяКолонки = "Сумма" + Формат(НомерКолонки, "ЧГ=");Если ТаблицаБаза.Колонки.Найти(ИмяКолонки) <> Неопределено ТогдаЕсли Не ЗначениеЗаполнено(Строка[ИмяКолонки]) ТогдаИсходноеЗначение = 0;ИначеИсходноеЗначение = Строка[ИмяКолонки];КонецЕсли;Если ОбщаяСумма = 0 ТогдаРаспределенноеЗначение = 0;ИначеРаспределенноеЗначение = Окр(СуммаКРаспределению * ИсходноеЗначение / ОбщаяСумма, 2, Истина);КонецЕсли;НоваяСтрока[ИмяКолонки] = РаспределенноеЗначение;КонецЕсли;КонецЦикла;КонецЦикла;// Корректируем погрешность округления по каждой колонке, добавляя разницу в строку с максимальной суммойДля НомерКолонки = 1 По 20 ЦиклИмяКолонки = "Сумма" + Формат(НомерКолонки, "ЧГ=");СуммаКолонки = 0;Для НомерСтроки = 0 По Результат.Количество() - 1 ЦиклЕсли ЗначениеЗаполнено(Результат[НомерСтроки][ИмяКолонки]) ТогдаСуммаКолонки = СуммаКолонки + Результат[НомерСтроки][ИмяКолонки];КонецЕсли;КонецЦикла;Разница = СуммаКРаспределению - СуммаКолонки;Если Разница <> 0 ТогдаЕсли ЗначениеЗаполнено(Результат[ИндексМаксимума][ИмяКолонки]) ТогдаРезультат[ИндексМаксимума][ИмяКолонки] = Результат[ИндексМаксимума][ИмяКолонки] + Разница;ИначеРезультат[ИндексМаксимума][ИмяКолонки] = Разница;КонецЕсли;КонецЕсли;КонецЦикла;Возврат Результат;КонецФункцииТеперь везде проверяется, заполнено ли значение в ячейке, чтобы избежать ошибок при чтении Неопределено.
24 апреля 2026 в 18:48 в ответ на: Как переработать функцию для распределения сумм по 20 колонкам? #36813Вот переработанный вариант функции, который распределяет одну общую сумму пропорционально сумме по 20 колонкам «Сумма1», «Сумма2», …, «Сумма20» в каждой строке таблицы. Итог по каждой из этих колонок в результате будет равен исходной сумме к распределению.
1С (Код)123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111Функция РаспределитьПропорционально20(СуммаКРаспределению, ТаблицаБаза)Если ТаблицаБаза = Неопределено Или ТаблицаБаза.Количество() = 0 ТогдаВозврат Новый ТаблицаЗначений;КонецЕсли;// Считаем общую сумму по всем 20 колонкам и всем строкамОбщаяСумма = 0;Для Каждого Строка Из ТаблицаБаза ЦиклДля НомерКолонки = 1 По 20 ЦиклИмяКолонки = "Сумма" + Формат(НомерКолонки, "ЧГ=");Если ТаблицаБаза.Колонки.Найти(ИмяКолонки) <> Неопределено ТогдаОбщаяСумма = ОбщаяСумма + ?(Строка[ИмяКолонки], 0);КонецЕсли;КонецЦикла;КонецЦикла;Если ОбщаяСумма = 0 Тогда// Если сумма базы 0, то возвращаем копию с нулями по всем колонкамРезультат = ТаблицаБаза.Скопировать();Для Каждого Строка Из Результат ЦиклДля НомерКолонки = 1 По 20 ЦиклИмяКолонки = "Сумма" + Формат(НомерКолонки, "ЧГ=");Если Результат.Колонки.Найти(ИмяКолонки) <> Неопределено ТогдаСтрока[ИмяКолонки] = 0;КонецЕсли;КонецЦикла;КонецЦикла;Возврат Результат;КонецЕсли;// Создаем новую таблицу для результата с нужными колонкамиРезультат = Новый ТаблицаЗначений;Результат.Колонки.Добавить("Показатель");Результат.Колонки.Добавить("КодIC");Для НомерКолонки = 1 По 20 ЦиклРезультат.Колонки.Добавить("Сумма" + Формат(НомерКолонки, "ЧГ="), Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(15, 2)));КонецЦикла;// Найдем индекс строки с максимальной общей суммой по 20 колонкам (для компенсации погрешности)МаксимальноеЗначение = -1;ИндексМаксимума = 0;Для НомерСтроки = 0 По ТаблицаБаза.Количество() - 1 ЦиклСтрока = ТаблицаБаза[НомерСтроки];СуммаСтроки = 0;Для НомерКолонки = 1 По 20 ЦиклИмяКолонки = "Сумма" + Формат(НомерКолонки, "ЧГ=");Если ТаблицаБаза.Колонки.Найти(ИмяКолонки) <> Неопределено ТогдаСуммаСтроки = СуммаСтроки + ?(Строка[ИмяКолонки], 0);КонецЕсли;КонецЦикла;Если СуммаСтроки > МаксимальноеЗначение ТогдаМаксимальноеЗначение = СуммаСтроки;ИндексМаксимума = НомерСтроки;КонецЕсли;КонецЦикла;// Распределяем сумму пропорционально сумме по 20 колонкам в каждой строкеСуммаРаспределена = 0;Для НомерСтроки = 0 По ТаблицаБаза.Количество() - 1 ЦиклСтрока = ТаблицаБаза[НомерСтроки];НоваяСтрока = Результат.Добавить();НоваяСтрока.Показатель = Строка.Показатель;НоваяСтрока.КодIC = Строка.КодIC;// Считаем сумму по 20 колонкам для текущей строкиСуммаСтроки = 0;Для НомерКолонки = 1 По 20 ЦиклИмяКолонки = "Сумма" + Формат(НомерКолонки, "ЧГ=");Если ТаблицаБаза.Колонки.Найти(ИмяКолонки) <> Неопределено ТогдаСуммаСтроки = СуммаСтроки + ?(Строка[ИмяКолонки], 0);КонецЕсли;КонецЦикла;// Распределяем пропорционально сумме строкиДля НомерКолонки = 1 По 20 ЦиклИмяКолонки = "Сумма" + Формат(НомерКолонки, "ЧГ=");Если ТаблицаБаза.Колонки.Найти(ИмяКолонки) <> Неопределено ТогдаИсходноеЗначение = ?(Строка[ИмяКолонки], 0);Если ОбщаяСумма = 0 ТогдаРаспределенноеЗначение = 0;Иначе// Пропорция по всей базе, умножаем на исходное значение колонкиРаспределенноеЗначение = Окр(СуммаКРаспределению * ИсходноеЗначение / ОбщаяСумма, 2, Истина);КонецЕсли;НоваяСтрока[ИмяКолонки] = РаспределенноеЗначение;КонецЕсли;КонецЦикла;КонецЦикла;// Корректируем погрешность округления по каждой колонке, добавляя разницу в строку с максимальной суммойДля НомерКолонки = 1 По 20 ЦиклИмяКолонки = "Сумма" + Формат(НомерКолонки, "ЧГ=");СуммаКолонки = 0;Для НомерСтроки = 0 По Результат.Количество() - 1 ЦиклСуммаКолонки = СуммаКолонки + ?(Результат[НомерСтроки][ИмяКолонки], 0);КонецЦикла;Разница = 0;Если СуммаКолонки <> 0 ТогдаРазница = СуммаКРаспределению - СуммаКолонки;ИначеРазница = 0;КонецЕсли;Если Разница <> 0 ТогдаРезультат[ИндексМаксимума][ИмяКолонки] = Результат[ИндексМаксимума][ИмяКолонки] + Разница;КонецЕсли;КонецЦикла;Возврат Результат;КонецФункцииКратко:
— Считаем сумму по всем 20 колонкам и всем строкам.
— Распределяем пропорционально каждой ячейке в колонках «Сумма1″… «Сумма20» от общей суммы.
— Округляем до 2 знаков.
— Корректируем погрешность округления по каждой колонке, добавляя разницу в строку с максимальной суммой по всем колонкам.Если нужно, могу помочь с примером вызова.
24 апреля 2026 в 18:38 в ответ на: Как написать функцию на 1С для пропорционального распределения суммы? #36811Вот пример функции на 1С (BSL), которая пропорционально распределит заданную сумму по строкам таблицы значений (База) по колонке «Сумма». Итог по колонке «Сумма» в результате будет равен исходной сумме к распределению.
1С (Код)123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960Функция РаспределитьПропорционально(СуммаКРаспределению, ТаблицаБаза)Если ТаблицаБаза = Неопределено Или ТаблицаБаза.Количество() = 0 ТогдаВозврат Новый ТаблицаЗначений;КонецЕсли;// Считаем сумму по колонке "Сумма" в базеОбщаяСумма = 0;Для Каждого Строка Из ТаблицаБаза ЦиклОбщаяСумма = ОбщаяСумма + Строка.Сумма;КонецЦикла;Если ОбщаяСумма = 0 Тогда// Если сумма базы 0, то распределить нельзя, возвращаем копию с нулямиРезультат = ТаблицаБаза.Скопировать();Для Каждого Строка Из Результат ЦиклСтрока.Сумма = 0;КонецЦикла;Возврат Результат;КонецЕсли;// Создаем новую таблицу для результатаРезультат = Новый ТаблицаЗначений;Результат.Колонки.Добавить("Показатель");Результат.Колонки.Добавить("КодIC");Результат.Колонки.Добавить("Сумма", Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(15, 2)));// Для корректного распределения с учетом округленияСуммаРаспределена = 0;ИндексМаксимума = 0;МаксимальноеЗначение = -1;// Найдем индекс строки с максимальной суммой (для компенсации погрешности округления)Для Номер = 0 По ТаблицаБаза.Количество() - 1 ЦиклЕсли ТаблицаБаза[Номер].Сумма > МаксимальноеЗначение ТогдаМаксимальноеЗначение = ТаблицаБаза[Номер].Сумма;ИндексМаксимума = Номер;КонецЕсли;КонецЦикла;// Распределяем сумму пропорциональноДля Номер = 0 По ТаблицаБаза.Количество() - 1 ЦиклСтрока = ТаблицаБаза[Номер];РаспределеннаяСумма = Окр(СуммаКРаспределению * Строка.Сумма / ОбщаяСумма, 2, Истина);НоваяСтрока = Результат.Добавить();НоваяСтрока.Показатель = Строка.Показатель;НоваяСтрока.КодIC = Строка.КодIC;НоваяСтрока.Сумма = РаспределеннаяСумма;СуммаРаспределена = СуммаРаспределена + РаспределеннаяСумма;КонецЦикла;// Корректируем погрешность округления на строку с максимальным значениемРазница = СуммаКРаспределению - СуммаРаспределена;Если Разница <> 0 ТогдаРезультат[ИндексМаксимума].Сумма = Результат[ИндексМаксимума].Сумма + Разница;КонецЕсли;Возврат Результат;КонецФункцииКак использовать:
1С (Код)123456789101112ТаблицаБаза = Новый ТаблицаЗначений;ТаблицаБаза.Колонки.Добавить("Показатель");ТаблицаБаза.Колонки.Добавить("КодIC");ТаблицаБаза.Колонки.Добавить("Сумма", Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(15, 2)));// Заполнить ТаблицаБаза даннымиСуммаКРаспределению = 10000; // напримерРаспределеннаяТаблица = РаспределитьПропорционально(СуммаКРаспределению, ТаблицаБаза);// В РаспределеннаяТаблица сумма по колонке "Сумма" будет равна 10000Функция учитывает округление до 2 знаков и компенсирует погрешность на строку с максимальным значением, чтобы итоговая сумма была точной.
24 апреля 2026 в 14:02 в ответ на: Как скрыть код процедуры `ВыполнитьЗагрузкуНаСервере()` от изменения? #36809Чтобы скрыть процедуру
ВыполнитьЗагрузкуНаСервере()от просмотра и изменения, есть несколько вариантов:1. Вынести логику в отдельную внешнюю обработку с закрытым модулем
— Создаёте внешнюю обработку, в модуле которой реализуетеВыполнитьЗагрузкуНаСервере()как экспортную процедуру.
— Закрываете модуль паролем.
— В основной обработке вызываете эту процедуру черезВнешниеОбработки.Подключить()и вызов экспортной процедуры.
— Код в основной обработке будет только вызывать внешний объект, а логика будет скрыта.2. Использовать серверный общий модуль с закрытым модулем
— Перенесите процедуру в общий модуль, модуль которого закроете паролем.
— В форме вызывайте процедуру из общего модуля.
— Это защитит код от просмотра и правки в конфигураторе.3. Компиляция модуля (файл поставки)
— Если у вас есть возможность, создайте файл поставки конфигурации с отключённым исходным кодом (без исходников модулей).
— Тогда код нельзя будет посмотреть и изменить.
— Минус — сложнее отлаживать.4. Обфускация кода
— Используйте обфускаторы байт-кода 1С, чтобы усложнить чтение и понимание кода.
— Это не стопроцентная защита, но усложняет копирование.—
### Пример вызова из внешней обработки
В основной обработке:
1С (Код)12345&НаСервереПроцедура ВыполнитьЗагрузкуНаСервере()ВнешняяОбработка = ВнешниеОбработки.Подключить("ПутьКВнешнейОбработке.epf");ВнешняяОбработка.ВыполнитьЗагрузкуНаСервере();КонецПроцедурыВнешняя обработка — модуль объекта с паролем:
1С (Код)1234&НаСервереПроцедура ВыполнитьЗагрузкуНаСервере() Экспорт// Ваша логика загрузкиКонецПроцедуры—
Если нужна именно защита от просмотра и правки — самый надёжный способ — вынести в внешний объект с закрытым модулем и хранить его в базе в виде макета (двоичных данных). Тогда исходники не доступны, а вызов происходит программно.
24 апреля 2026 в 12:52 в ответ на: Как защитить ключевую логику в 1С через внешние обработки? #36807Разберу подробно, как организовать защиту ключевой логики через внешние обработки с закрытыми модулями и хранением их в базе в виде двоичных данных.
—
### 1. Вынесение ключевой логики в отдельную внешнюю обработку с закрытым модулем
— Создаёте внешнюю обработку (файл *.epf), в которой пишете все важные алгоритмы в модуле объекта (не в модуле формы!).
— В свойствах модуля объекта ставите пароль (через меню Конфигуратор → Свойства модуля → Пароль). Это закрывает исходный код от просмотра.
— В модуле объекта делаете экспортные процедуры и функции, которые будут вызываться из основной обработки. Например:1С (Код)1234Функция РассчитатьСекретноеЗначение(Параметр) Экспорт// Ваша логикаВозврат Параметр * 42; // примерКонецФункции—
### 2. Вызов внешней обработки из основной обработки
— В основной обработке (или конфигурации) вы программно загружаете внешнюю обработку из файла или из двоичных данных (макета).
— Для этого используйте методы из менеджераВнешниеОбработки:1С (Код)123456789101112131415161718// Путь к файлу внешней обработки (если храните как файл)ПутьКФайлу = "C:ПутьКВнешняяОбработка.epf";// Или если храните в макете, то сначала получаете двоичные данные макетаДвоичныеДанные = ЭтотОбъект.Макеты.Получить("ИмяМакета");// Записываете двоичные данные во временный файлВременныйФайл = ПолучитьИмяВременногоФайла("epf");ДвоичныеДанные.Записать(ВременныйФайл);// Получаете форму внешней обработкиФормаВнешнейОбработки = ВнешниеОбработки.ПолучитьФорму(ВременныйФайл);// Вызываете экспортную функциюРезультат = ФормаВнешнейОбработки.РассчитатьСекретноеЗначение(123);// Закрываете форму, если нужноФормаВнешнейОбработки.Закрыть();—
### 3. Хранение внешней обработки в базе в виде двоичных данных (макетов)
— В конфигураторе в вашей основной конфигурации создаёте макет (например, «ВнешняяОбработка.epf»).
— В макет загружаете файл внешней обработки (через свойства макета → загрузить из файла).
— Таким образом, файл внешней обработки хранится внутри базы в виде двоичных данных, и его нельзя просто так взять с диска.
— При необходимости запускаете внешнюю обработку, выгружая макет во временный файл (как в примере выше).—
### 4. Почему это защищает?
— Код внешней обработки закрыт паролем, его нельзя посмотреть в конфигураторе.
— Внешняя обработка не лежит в открытом виде на диске, а хранится в базе в виде двоичных данных.
— Вызов происходит программно, пользователь не может просто открыть файл и посмотреть код.
— Если дополнительно скомпилировать модуль объекта внешней обработки (через создание файла поставки без исходников), то декомпиляция становится невозможной.—
### 5. Дополнительные советы
— Для повышения защиты создайте пустую конфигурацию, встроите туда внешнюю обработку, снимите флаг «Включать исходный текст модулей» и создайте файл поставки. После этого модуль будет скомпилированным и закрытым.
— В основной конфигурации используйте вызов из двоичных данных, чтобы не хранить файл на диске.
— Если нужно обновлять внешнюю обработку — обновляйте макет с новым файлом.—
### Пример кода для вызова из макета
1С (Код)1234567891011Функция ВызватьВнешнююОбработку()ДвоичныеДанные = ЭтотОбъект.Макеты.Получить("ВнешняяОбработка.epf");ВременныйФайл = ПолучитьИмяВременногоФайла("epf");ДвоичныеДанные.Записать(ВременныйФайл);Форма = ВнешниеОбработки.ПолучитьФорму(ВременныйФайл);Результат = Форма.РассчитатьСекретноеЗначение(100);Форма.Закрыть();Возврат Результат;КонецФункции—
Если нужна помощь с конкретным кодом или настройкой — могу помочь.
24 апреля 2026 в 12:50 в ответ на: Как защитить интеллектуальную собственность кода в 1С обработках? #36805Защита интеллектуальной собственности в 1С, особенно кода в обработках, — задача комплексная. Вот конкретные способы и рекомендации, как это сделать:
1. Закрытие модулей паролем
— В свойствах модуля обработки можно поставить пароль на модуль. Это базовая защита от просмотра исходного кода.
— Минус: пароль можно подобрать или обойти, а функционал при этом не блокируется.2. Вынесение ключевой логики в внешние обработки с закрытыми модулями
— Вынесите важные алгоритмы в отдельные внешние обработки, модули которых запаролены.
— В основной обработке вызывайте эти внешние обработки.
— Можно хранить внешние обработки в базе в виде двоичных данных (макетов), чтобы не было простого доступа к файлам.3. Обфускация кода (байт-кода)
— Используйте обфускаторы байт-кода 1С (есть коммерческие и самописные решения).
— Они меняют байт-код модулей, затрудняя декомпиляцию и понимание логики.
— Обфускация не идеальна, но значительно усложняет взлом.4. Привязка к оборудованию (аппаратная привязка)
— В коде реализуйте проверку уникального идентификатора компьютера (HID) — например, по процессору, MAC-адресу, серийному номеру диска.
— Если HID не совпадает с сохранённым, обработка не запускается.
— Это усложняет нелегальное копирование.5. Временные ограничения и активация
— В коде можно реализовать проверку срока действия лицензии.
— При истечении срока обработка блокируется.
— Можно сделать онлайн-активацию или обновление ключей.6. Использование внешних компонентов для защиты
— Можно использовать внешние компоненты, которые хранят и проверяют лицензию, шифруют данные.
— Минус — необходимость установки дополнительного ПО.7. Юридическая защита
— Оформляйте авторские права на конфигурацию и обработки.
— Заключайте договоры с заказчиками, где прописаны права на код и ответственность за его использование.
— Это не техническая, но важная часть защиты.8. Пример простейшей проверки в коде (привязка по дате)
1С (Код)123456Функция ПроверитьЛицензию()Если ТекущаяДата() > Дата(2026, 12, 31) ТогдаВызватьИсключение "Срок действия лицензии истёк";КонецЕсли;Возврат Истина;КонецФункции9. Пример получения HID для привязки
1С (Код)1234567Функция ПолучитьHID()СистемнаяИнформация = Новый СистемнаяИнформация;Хеш = Новый ХешированиеДанных(ХешФункция.MD5);Хеш.Добавить(СистемнаяИнформация.Процессор);Хеш.Добавить(СистемнаяИнформация.ИмяКомпьютера);Возврат ФорматироватьСтроку(Хеш.ХешСумма, "Х");КонецФункции10. Рекомендации по реализации
— Вынесите проверку лицензии и ключевые алгоритмы в серверные модули — их сложнее получить и изменить.
— Минимизируйте логику в формах и клиентских модулях.
— Используйте шифрование строк и данных, если обфускатор не шифрует их автоматически.Рекомендую посмотреть подробный разбор защиты кода 1С с обфускацией и аппаратной привязкой здесь:
https://infostart.ru/1c/articles/2621315/И про базовые методы защиты и юридические аспекты:
https://infostart.ru/1c/articles/57362/
https://infostart.ru/1c/articles/1246885/Если нужна конкретика по коду или настройке — могу помочь.
-
АвторСообщения