При изучении программирования в 1С, особенно проходя примеры из «Практического пособия разработчика» (например, М.Г. Радченко), многие сталкиваются с ошибками типов данных на этапе проведения документов расчета зарплаты. Одной из самых частых и сбивающих с толку ошибок является сообщение: «Преобразование значения к типу Число не может быть выполнено».
В этой статье мы подробно разберем, почему возникает эта ошибка в обработчике проведения, как диагностировать проблему с помощью отладчика и какие существуют способы её устранения: как на уровне пользовательских данных, так и на уровне программного кода.
Рассмотрим ситуацию, описанную в вопросе. Ошибка возникает в общем модуле ПроведениеРасчетов в процедуре расчета начислений. Платформа указывает на конкретную строку кода:
ЗаписьРегистра.Результат = (ЗаписьРегистра.ИсходныеДанные/ВыборкаРезультата.Норма) * ВыборкаРезультата.Факт;
Суть ошибки «Преобразование значения к типу Число не может быть выполнено» заключается в том, что один из операндов в этой формуле не является числом. Система 1С:Предприятие пытается выполнить математические операции (деление и умножение), но встречает тип данных, который невозможно автоматически привести к числу. Чаще всего это типы Null, Неопределено или, реже, Строка, содержащая нечисловые символы.
Давайте проанализируем компоненты формулы:
ЗаписьРегистра.ИсходныеДанные — значение, которое берется из ресурса регистра (обычно заполняется при формировании движений в модуле документа).ВыборкаРезультата.Норма — данные, полученные из запроса к графику работы.ВыборкаРезультата.Факт — данные, также полученные из запроса к графику.Если хотя бы одна из этих переменных содержит Null (значение базы данных, обозначающее отсутствие данных), вычисление всей формулы падает с ошибкой, так как в языке 1С операция Число * Null или Число / Null недопустима.
В ходе обсуждения выяснилось, что наиболее вероятной причиной является получение пустых значений (NULL) из запроса к виртуальной таблице графика. Давайте посмотрим на текст запроса, который используется в коде:
"ВЫБРАТЬ
| НачисленияДанныеГрафика.ЗначениеПериодДействия КАК Норма,
| НачисленияДанныеГрафика.ЗначениеФактическийПериодДействия КАК Факт,
...
|ИЗ
| РегистрРасчета.Начисления.ДанныеГрафика(...)
| КАК НачисленияДанныеГрафика";
Виртуальная таблица ДанныеГрафика работает по принципу левого соединения (Left Join) основной таблицы регистра расчета с таблицей регистра сведений, содержащего графики работы. Соединение происходит по измерению ГрафикРаботы и датам периода действия.
Суть проблемы: Если на конкретную дату (или период), за который производится расчет, в регистре сведений (графике) отсутствуют записи, то соединение не находит соответствия. В результате поля Норма и Факт возвращают значение NULL.
В примере из темы проблема заключалась в следующем:
Почему автор вопроса утверждал, что в отладчике он видит числа? Это распространенная ошибка при отладке циклов. В цикле Для Каждого ЗаписьРегистра Из НаборЗаписейРегистра может обрабатываться несколько строк (несколько сотрудников).
NULL, и программа падает.Чтобы поймать ошибку, необходимо использовать Точку останова с условием или просматривать значения переменных непосредственно в момент падения (когда конфигуратор останавливается на строке с ошибкой). В табло (Shift+F9) нужно проверить:
ВыборкаРезультата.НормаВыборкаРезультата.ФактЗаписьРегистра.ИсходныеДанныеРассмотрим два уровня решения проблемы: исправление пользовательских данных и доработка кода для повышения отказоустойчивости.
Это то, что помогло автору темы. Если ошибка возникла из-за невнимательности при вводе данных:
ГрафикиРаботы и связанный с ним регистр сведений (обычно ГрафикиРаботы).Даже если пользователь ошибся с датой, программа не должна "падать" с критической ошибкой платформы. Хорошим тоном программирования является обработка возможных значений NULL непосредственно в запросе.
Для этого используйте функцию языка запросов ЕСТЬNULL (ISNULL). Она позволяет заменить NULL на значение по умолчанию (обычно 0) на этапе выборки данных.
Изменим текст запроса в общем модуле следующим образом:
Запрос.Текст =
"ВЫБРАТЬ
| ЕСТЬNULL(НачисленияДанныеГрафика.ЗначениеПериодДействия, 0) КАК Норма,
| ЕСТЬNULL(НачисленияДанныеГрафика.ЗначениеФактическийПериодДействия, 0)
| КАК Факт,
| НачисленияДанныеГрафика.НомерСтроки КАК НомерСтроки
|ИЗ
| РегистрРасчета.Начисления.ДанныеГрафика(Регистратор = &Регистратор И
| ВидРасчета = &ВидРасчета И Сотрудник В (&СписокСотрудников))
| КАК НачисленияДанныеГрафика";
Что это даст?
Норма и Факт вернут число 0 вместо NULL.
Если ВыборкаРезультата.Норма = 0 Тогда
// Вывод сообщения пользователю о том, что нет рабочих дней
ЗаписьРегистра.Результат = 0;
Иначе
// Расчет выполняется корректно
КонецЕсли;
Таким образом, вместо падения программы пользователь получит понятное сообщение: "Вид расчета: Оклад – Нет рабочих дней в заданном периоде".
Хотя в данном случае проблема была в графике, не стоит забывать про переменную ЗаписьРегистра.ИсходныеДанные. Она заполняется в модуле документа при формировании движений:
Движение.ИсходныеДанные = ТекСтрокаНачисления.Начислено;
Если в документе колонка "Начислено" не заполнена, а тип значения допускает пустые ссылки или Неопределено, это также может привести к ошибке. Однако для числовых ресурсов регистра, если не задано иное, пустое значение обычно преобразуется в 0 при записи. Тем не менее, рекомендуется всегда контролировать заполненность реквизитов документа перед проведением, используя метод ПроверитьЗаполнение().
Ошибка «Преобразование значения к типу Число не может быть выполнено» при расчете зарплаты почти всегда означает, что запрос к виртуальной таблице ДанныеГрафика вернул NULL из-за отсутствия календарных данных за указанный период. Чтобы исправить это, нужно заполнить графики работы на нужный год. Чтобы предотвратить ошибку в будущем — обернуть поля запроса в функцию ЕСТЬNULL(Поле, 0).