При разработке печатных форм в системе «1С:Предприятие» перед разработчиками часто возникает задача вывода денежных сумм или количественных показателей прописью. Это стандартное требование для финансовой документации: чеков, расходных кассовых ордеров, актов приемки-передачи и договоров. В этой статье мы подробно разберем, как правильно реализовать вывод чисел прописью, почему нельзя использовать эту функцию напрямую в запросе, как исправить типичные ошибки адресации к выборкам и как задействовать альтернативные способы форматирования.
Название темы на форуме часто вводит в заблуждение новичков: «ЧислоПрописью в запросе». Важно раз и навсегда уяснить базовое правило архитектуры платформы: в тексте запроса (на языке запросов 1С) использовать функцию ЧислоПрописью() нельзя.
Язык запросов 1С транслируется платформой в SQL-запросы, которые выполняются непосредственно на сервере СУБД (Microsoft SQL Server, PostgreSQL, IBM DB2 или Oracle). СУБД оперирует только стандартными типами данных (числа, строки, даты, булево) и не содержит встроенных механизмов для сложного морфологического разбора и склонения числительных по правилам русского (или любого другого) языка.
Преобразование числовых значений в текстовые эквиваленты всегда выполняется на более поздних этапах обработки данных:
Давайте подробно рассмотрим, как правильно реализовать первый (классический) вариант в коде формирования печатной формы.
Проанализируем исходную задачу. У нас есть документ Salary (Зарплата), содержащий табличную часть со списком сотрудников и начисленной суммой в поле CheckW2. Нам необходимо вывести эти данные в печатную форму чека, преобразовав сумму в текстовый формат.
Рассмотрим структуру кода обхода выборки, где часто совершают ошибки начинающие разработчики:
// НЕКОРРЕКТНЫЙ ФРАГМЕНТ КОДА
Пока ВыборкаSalary.Следующий() Цикл
ОбластьSalary.Параметры.Заполнить(ВыборкаSalary);
// Попытка присвоить значение прописи, обращаясь к выборке документа, а не табличной части:
ОбластьSalary.Параметры.CheckW2 = ЧислоПрописью(Выборка.CheckW2, , ",,,,,,,,2" );
ТабДок.Вывести(ОбластьSalary, ВыборкаSalary.Уровень());
КонецЦикла;
При запуске такого кода система выдаст ошибку выполнения: Поле объекта не обнаружено (CheckW2). Выясним причину ее возникновения.
В документе присутствует двухэтапный обход данных. Первый цикл (внешний) обходит выборку документов (переменная Выборка). Второй цикл (внутренний) обходит строки табличной части этого документа (переменная ВыборкаSalary). Реквизит CheckW2 принадлежит строке табличной части, а не шапке документа.
Следовательно, обращаться к реквизиту во внутреннем цикле нужно строго через переменную внутренней выборки — ВыборкаSalary.CheckW2. Если обратиться к Выборка.CheckW2, платформа попытается найти это поле в шапке документа, не обнаружит его и завершит работу аварийно.
Также важно избегать случайных опечаток, таких как двойные точки (например, ВыборкаSalary..CheckW2), которые приводят к синтаксической ошибке на этапе компиляции модуля.
Исправленный и полностью работоспособный вариант кода выглядит следующим образом:
Процедура Check(ТабДок, Ссылка) Экспорт
Макет = Документы.Salary.ПолучитьМакет("Check");
Запрос = Новый Запрос;
Запрос.Текст = "
|ВЫБРАТЬ
| Salary.Ссылка КАК Ссылка,
| Salary.Номер КАК Номер,
| Salary.Дата КАК Дата,
| Salary.Salary.(
| Ссылка КАК Ссылка,
| НомерСтроки КАК НомерСтроки,
| Сотрудник КАК Сотрудник,
| CheckW2 КАК CheckW2
| ) КАК Salary
|ИЗ
| Документ.Salary КАК Salary
|ГДЕ
| Salary.Ссылка В (&Ссылка)";
Запрос.Параметры.Вставить("Ссылка", Ссылка);
Выборка = Запрос.Выполнить().Выбрать();
ОбластьЗаголовок = Макет.ПолучитьОбласть("Заголовок");
Шапка = Макет.ПолучитьОбласть("Шапка");
ОбластьSalaryШапка = Макет.ПолучитьОбласть("SalaryШапка");
ОбластьSalary = Макет.ПолучитьОбласть("Salary");
ТабДок.Очистить();
ВставлятьРазделительСтраниц = Ложь;
Пока Выборка.Следующий() Цикл
Если ВставлятьРазделительСтраниц Тогда
ТабДок.ВывестиГоризонтальныйРазделительСтраниц();
КонецЕсли;
ТабДок.Вывести(ОбластьЗаголовок);
Шапка.Параметры.Заполнить(Выборка);
ТабДок.Вывести(Шапка, Выборка.Уровень());
ТабДок.Вывести(ОбластьSalaryШапка);
ВыборкаSalary = Выборка.Salary.Выбрать();
Пока ВыборкаSalary.Следующий() Цикл
// Сначала заполняем параметры стандартным образом
ОбластьSalary.Параметры.Заполнить(ВыборкаSalary);
// Затем переопределяем параметр суммы его текстовым представлением
СуммаЧислом = ВыборкаSalary.CheckW2;
ОбластьSalary.Параметры.CheckW2 = ЧислоПрописью(СуммаЧислом, , ",,,,,,,,2");
ТабДок.Вывести(ОбластьSalary, ВыборкаSalary.Уровень());
КонецЦикла;
ВставлятьРазделительСтраниц = Истина;
КонецЦикла;
КонецПроцедуры
Рассмотрим синтаксис функции встроенного языка ЧислоПрописью(). Она имеет следующий формат описания:
ЧислоПрописью(Число, ФорматнаяСтрока, ПараметрыПредметаИсчисления)
Полная структура строки параметров предмета исчисления для российского рубля выглядит так:
"рубль, рубля, рублей, м, копейка, копейки, копеек, ж, 2"
Где первые четыре параметра описывают целую часть (название в ед. ч., род. падеже ед. ч., род. падеже мн. ч. и род), следующие четыре — дробную часть, а последний символ (цифра 2) задает разрядность округления.
Лайфхак с пустой форматной строкой ",,,,,,,,2":
Если в коде передать строку параметров в виде одних только запятых с двойкой на конце, платформа уберет текстовые названия валют (рубли и копейки), но сохранит правила вывода дробной части. Рассмотрим на примерах:
ЧислоПрописью(125.45, , ",,,,,,,,2") вернет текстовую строку: «Сто двадцать пять 45».ЧислоПрописью(125.45, , ",,,,,,,,0") вернет значение без копеек: «Сто двадцать пять» (произойдет округление до целого числа).Этот прием крайне полезен, когда вам нужно вывести число словами, но без привязки к конкретной денежной единице, или если название валюты выводится в макете отдельной статической строкой.
Профессиональные разработчики 1С стараются минимизировать объем ручного кода форматирования в модулях программных объектов. Платформа предоставляет мощную альтернативу — использование конструктора форматных строк прямо в ячейках макета.
Проанализируем этот метод пошагово:
CheckW2).ЧП) или «Локальная пропись денежных сумм» (код формата ЧПДС).В результате в свойстве «Формат» будет записано выражение вида ЧП или ЧПДС. При выводе этой области макета программный код упростится до предела:
Пока ВыборкаSalary.Следующий() Цикл
// Платформа сама преобразует число в пропись на лету по правилам формата ячейки!
ОбластьSalary.Параметры.Заполнить(ВыборкаSalary);
ТабДок.Вывести(ОбластьSalary, ВыборкаSalary.Уровень());
КонецЦикла;
Это делает код более чистым, легко читаемым и упрощает последующую поддержку печатной формы, если требования заказчика к визуальному оформлению изменятся.
Если вы ведете разработку в типовой конфигурации («Бухгалтерия предприятия», «Зарплата и управление персоналом», «ERP» или «Управление нашей фирмой»), вам не обязательно вручную прописывать параметры валют. В составе БСП есть готовые программные интерфейсы для работы с денежными суммами.
Выясним, как использовать метод общего модуля для автоматического формирования суммы прописью с привязкой к валюте документа:
// Пример использования механизмов БСП
ВалютаДокумента = Ссылка.Валюта; // Получаем ссылку на справочник "Валюты"
СуммаЧислом = ВыборкаSalary.CheckW2;
// Вызов стандартной функции БСП:
СуммаПрописью = РаботаСКурсамиВалют.СформироватьСуммуПрописью(СуммаЧислом, ВалютаДокумента);
ОбластьSalary.Параметры.CheckW2 = СуммаПрописью;
Преимущества использования БСП: