Почему при программном проведении документа в 1С 7.7 сбрасывается дробная часть количества?

Программист 1С v7.7
← На главную

В практике разработчика на платформе 1С:Предприятие 7.7 нередко возникает ситуация: при ручном вводе и проведении документа через интерфейс (кнопкой на форме) все данные сохраняются корректно, включая дробную часть количества. Однако, стоит запустить программную обработку, которая выполняет метод Провести(), как дробная часть реквизитов (например, точность которых равна 3) внезапно обнуляется, оставляя только целое число. Рассмотрим подробно, почему это происходит и как исправить данную ошибку.

Анализ механизма проведения в 1С 7.7

Для начала разберем, как работает метод Провести(). В отличие от современных версий платформы, в 7.7 вызов этого метода инициирует сложную цепочку событий. Проанализируем последовательность:

  1. Система проверяет статус документа и возможность его записи.
  2. Вызывается предопределенная процедура ПриЗаписи() в модуле документа.
  3. Если запись прошла успешно, управление передается в процедуру ОбработкаПроведения().

Проблема «сброса» дробной части обычно кроется не в самой обработке, которая вызывает проведение, а во внутреннем коде модуля документа. Разберем основные причины по шагам.

Причина 1: Различие контекста формы и программного объекта

Когда вы работаете с документом через форму, элементы управления (поля ввода) жестко связаны с метаданными. Проанализируем ситуацию: если на форме поле настроено на отображение 3 знаков после запятой, пользователь видит и вводит эти знаки. Однако программный вызов СоздатьОбъект("Документ.ИмяДокумента") работает напрямую с базой данных.

Выясним важный нюанс: если в конфигураторе для конкретного реквизита установлена точность 0, но на форме программно или в свойствах поля вывода указано «3 знака», то при интерактивной работе значение может удерживаться в памяти формы до момента окончательной записи. При программном же проведении через Провести(), объект может быть записан с отсечением разрядов, если тип данных в метаданных не соответствует ожидаемой точности.

Причина 2: Логика процедуры ОбработкаПроведения

Рассмотрим пример кода из сообщения пользователя, где используется вызов:

СФ.Провести(,"Авт");

Здесь второй параметр "Авт" является строковым значением, которое передается внутрь модуля документа. Проанализируем, что происходит внутри модуля документа (СчетФактура или АктВозврата). Часто программисты пишут условия следующего вида:


Процедура ОбработкаПроведения(ВидПроведения)
    Если ВидПроведения = "Авт" Тогда
        // Специфическая логика для программного проведения
        // Например, пересчет количества по документам-основаниям
    КонецЕсли;
КонецПроцедуры

Если внутри такого условия встречается функция Окр() или происходит присваивание переменной, которая ранее была инициализирована как целое число, дробная часть будет потеряна. Проблема в том, что при интерактивном проведении (нажатием кнопки) этот параметр пуст, и код выполняется по другой ветке, где ошибки нет.

Причина 3: Пересчет в процедуре ПриЗаписи

Посмотрим на ситуацию, когда дробная часть исчезает еще до попадания в регистры. Метод Провести() всегда вызывает сохранение объекта. Если в модуле документа в процедуре ПриЗаписи() реализован алгоритм автоматического распределения или пересчета сумм/количества, он может содержать ошибки округления.

Рассмотрим подробнее пример некорректного кода:


Процедура ПриЗаписи()
    ВыбратьСтроки();
    Пока ПолучитьСтроку() = 1 Цикл
        // Ошибка: принудительное округление до целого
        Количество = Цел(Количество); 
    КонецЦикла;
КонецПроцедуры

Как найти и исправить ошибку: пошаговая инструкция

Чтобы локализовать проблему, выполним следующие действия:

Шаг 1. Проверка метаданных

Откройте Конфигуратор и найдите нужный документ. Перейдите на вкладку «Реквизиты» (или в табличную часть). Проверьте свойства реквизита Количество. Убедитесь, что в поле «Точность» стоит значение 3 (или иное требуемое), а не 0.

Шаг 2. Изучение ОбработкиПроведения

Откройте модуль документа. Найдите процедуру ОбработкаПроведения(КонтекстПараметр). Проанализируйте, как используется входящий параметр. Если ваша обработка передает специфическую строку (как "Авт" в примере), найдите в модуле документа все вхождения этой строки. Скорее всего, там обнаружится вызов функции Окр() или работа с временными таблицами, где точность не соблюдена.

Шаг 3. Использование отладчика

Запустите программное проведение под отладкой. Установите точку останова в начале процедуры ОбработкаПроведения. Проверьте значения в табличной части документа (Количество) сразу при входе в процедуру и после выполнения подозрительных функций пересчета. Это позволит точно определить строку кода, «съедающую» знаки после запятой.

Рекомендация по написанию кода проведения

Проанализируем фрагмент кода из обсуждения, который вызвал нарекания у опытных участников форума из-за «лестничной» структуры. Постараемся переписать его более оптимально, чтобы избежать логических ошибок при вложенных циклах:


СФ = СоздатьОбъект("Документ.СчетФактура");
СФ.ВыбратьДокументы(Дата1, Дата2);
Пока СФ.ПолучитьДокумент() = 1 Цикл
    Если Список.Принадлежит(СФ.Склад) = 0 Тогда
        Продолжить;
    КонецЕсли;

    Состояние("Обработка: " + СФ.НомерДок);
    
    // Пытаемся провести документ
    Если СФ.Провести(,"Авт") = 0 Тогда
        Протокол.ДобавитьСтроку("СФ " + СФ.НомерДок + " - Ошибка проведения");
        Прервать;
    КонецЕсли;

    Протокол.ДобавитьСтроку("СФ " + СФ.НомерДок + " проведен");
    
    // Работа с подчиненными документами
    АВ = СоздатьОбъект("Документ");
    АВ.ВыбратьПодчиненныеДокументы(,, СФ.ТекущийДокумент());
    Пока АВ.ПолучитьДокумент() = 1 Цикл
        Если АВ.Вид() <> "АктВозврата" Тогда
            Продолжить;
        КонецЕсли;
        
        Если АВ.ПроводитьПриЗаписи = 0 Тогда
            Если АВ.Провести(,"Авт") = 1 Тогда
                Протокол.ДобавитьСтроку("-> АВ " + АВ.НомерДок + " проведен");
            Иначе
                Протокол.ДобавитьСтроку("-> АВ " + АВ.НомерДок + " - ОШИБКА");
            КонецЕсли;
        КонецЕсли;
    КонецЦикла;
КонецЦикла;

Подведение итогов

Подводя итог, можно сказать, что в 1С 7.7 метод Провести() сам по себе не округляет числа. Округление происходит либо из-за недостаточной точности в метаданных, либо из-за специфического кода в модуле документа, который реагирует на параметры программного вызова. Всегда проверяйте соответствие точности реквизитов в конфигураторе и логику обработки параметров в процедурах ПриЗаписи и ОбработкаПроведения.

← На главную