Как программно изменить вид операции документа "Реализация товаров и услуг" в 1С?

Программист 1С v8.3 (Управляемые формы) 1С:Управление торговлей Бухгалтерский учет Торговля и дистрибуция
← На главную

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

Понимание вида операции и его влияния на учет

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

  1. Форма документа и доступные реквизиты: От выбранного вида операции напрямую зависит, как будет выглядеть форма документа. Могут появляться или исчезать целые секции, меняться доступность полей для заполнения. Например, для реализации товаров могут быть доступны поля, связанные с отгрузкой и ценообразованием, тогда как для реализации услуг — поля, специфичные для описания оказываемых услуг.

  2. Проводки и регистры: Это, пожалуй, наиболее существенное изменение. Каждый вид операции соответствует определенной хозяйственной операции и влияет на бухгалтерский и налоговый учет по-разному. Например:

    • Вид операции "Реализация (Товары)" формирует проводки по списанию себестоимости реализованных товаров и отражению выручки.
    • Вид операции "Услуги" обычно формирует проводки только по выручке, так как себестоимость услуг может формироваться иным образом или отсутствовать как таковая.
    • Вид операции "Продажа, комиссия" будет влиять на учет комиссионного вознаграждения и расчеты с комитентом.

    Изменение вида операции без перепроведения документа не приведет к изменению движений по регистрам, что критически важно для корректного учета.

  3. Заполнение табличных частей: Вид операции может ограничивать типы номенклатуры, которые можно подобрать в табличные части. Например, в документ с видом операции "Товары" может быть невозможно подобрать номенклатуру с типом "Услуга", и наоборот.

  4. Документы-основания и связанные документы: Изменение вида операции может повлиять на возможность создания документов-оснований (например, счета на оплату) или связанных документов (например, счета-фактуры выданные, возвраты товаров от покупателя), а также на их заполнение.

Анализ первоначальных ошибок и некорректных подходов

Часто при попытке программного изменения документов возникают типичные ошибки, связанные с неправильным использованием методов работы с объектами 1С. Рассмотрим распространенные заблуждения на основе представленного кода.

Пример 1: Использование Документы.Выбрать() и НайтиПоНомеру()

Изначально была предпринята попытка изменить документы с помощью комбинации метода Выбрать() и НайтиПоНомеру() внутри цикла:


&НаСервере
Процедура ИзменитьРеализациюНаСервере()
    ВыборкаДокументы = Документы.РеализацияТоваровУслуг.Выбрать(Объект.НачПериода, Объект.КонПериода);
    Пока ВыборкаДокументы.Следующий() Цикл
        // Ошибка 1: Здесь Вы всегда пытаетесь найти один и тот же документ по номеру,
        // игнорируя текущий документ из выборки.
        ДокОбъект = Документы.РеализацияТоваровУслуг.НайтиПоНомеру("10000000078");
        
        // Ошибка 2: Эта строка перезаписывает предыдущую, но при этом
        // ДокОбъект = ВыборкаДокументы.ПолучитьОбъект; - некорректно для ВыборкиПоЗначению,
        // нужно использовать Ссылка.ПолучитьОбъект()
        ДокОбъект = ВыборкаДокументы.ПолучитьОбъект; 
        
        ДокОбъект.ВидОперации = Перечисления.ВидыОперацийРеализацияТоваров.Услуги;
        
        // Ошибка 3: Метод Записать() требует скобок.
        ДокОбъект.Записать; 
    КонецЦикла;
КонецПроцедуры

Здесь мы видим несколько проблем:

  1. Внутри цикла, который должен был бы обрабатывать документы из ВыборкаДокументы, происходит повторный поиск документа по жестко заданному номеру "10000000078". Это означает, что фактически обрабатывался бы только один документ (если найден) или никакой, если его нет, а не все документы из выборки.

  2. Метод ПолучитьОбъект вызывается непосредственно у объекта выборки (ВыборкаДокументы.ПолучитьОбъект). Для выборки, полученной через Документы.Выбрать() (это ВыборкаПоЗначению), чтобы получить объект документа, необходимо сначала получить его ссылку, а затем у ссылки вызвать метод ПолучитьОбъект(), то есть ВыборкаДокументы.Ссылка.ПолучитьОбъект(). В данном случае это привело бы к ошибке выполнения.

  3. Вызов метода Записать был без скобок: ДокОбъект.Записать;. Корректный вызов метода всегда подразумевает скобки, даже если нет параметров: ДокОбъект.Записать();.

Пример 2: Использование НайтиПоРеквизиту()

Следующая попытка была с использованием метода НайтиПоРеквизиту():


Процедура ИзменитьРеализациюНаСервере()
    ВыборкаДокументы = Документы.РеализацияТоваровУслуг.НайтиПоРеквизиту("ВидОперации", Перечисления.ВидыОперацийРеализацияТоваров.ПродажаКомиссия);
    Пока ВыборкаДокументы.Следующий() Цикл // Ошибка: Метод объекта не обнаружен (Следующий)
        ДокОбъект = ВыборкаДокументы.ПолучитьОбъект;
        ДокОбъект.ВидОперации = Перечисления.ВидыОперацийРеализацияТоваров.Услуги;
        ДокОбъект.Записать();
        Сообщить(ДокОбъект.ВерсияДанных);
    КонецЦикла;
КонецПроцедуры

Здесь мы столкнулись с ошибкой: "Метод объекта не обнаружен (Следующий)". Причина в том, что метод Документы.РеализацияТоваровУслуг.НайтиПоРеквизиту() возвращает либо ссылку на документ (если найден один), либо коллекцию ссылок (например, Массив или СписокЗначений, если найдено несколько), либо Неопределено. Он не возвращает объект типа "Выборка из таблицы" или "Выборка по значению", у которого есть метод Следующий(). Соответственно, попытка вызвать Следующий() у такого объекта приводит к ошибке.

Корректное решение: Использование запроса для выборки документов

Наиболее надежным и гибким способом массовой выборки документов для программной обработки является использование объекта Запрос.

Разберем по шагам, как правильно сформулировать запрос и обработать его результат.

Шаг 1: Формирование запроса

Создадим новый объект Запрос и зададим его текст. Мы хотим выбрать ссылки на документы "Реализация товаров и услуг", у которых текущий вид операции равен "Продажа, комиссия".


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |    РеализацияТоваровУслуг.Ссылка
    |ИЗ
    |    Документ.РеализацияТоваровУслуг КАК РеализацияТоваровУслуг
    |ГДЕ
    |    РеализацияТоваровУслуг.ВидОперации = &ВидОперации";

Пояснения к запросу:

Также, при необходимости, мы можем добавить дополнительные условия, например, по периоду:


Запрос.Текст = 
    "ВЫБРАТЬ
    |    РеализацияТоваровУслуг.Ссылка
    |ИЗ
    |    Документ.РеализацияТоваровУслуг КАК РеализацияТоваровУслуг
    |ГДЕ
    |    РеализацияТоваровУслуг.ВидОперации = &ВидОперации
    |    И РеализацияТоваровУслуг.Дата МЕЖДУ &ПериодНачало И &ПериодОкончания";

Шаг 2: Установка параметров запроса

Перед выполнением запроса необходимо установить значения для всех его параметров:


Запрос.УстановитьПараметр("ВидОперации", Перечисления.ВидыОперацийРеализацияТоваров.ПродажаКомиссия);
// Если добавлено условие по периоду:
// Запрос.УстановитьПараметр("ПериодНачало", НачалоДня(Объект.НачПериода));
// Запрос.УстановитьПараметр("ПериодОкончания", КонецДня(Объект.КонПериода));

Здесь мы устанавливаем значение для параметра &ВидОперации в перечисление Перечисления.ВидыОперацийРеализацияТоваров.ПродажаКомиссия. Это означает, что мы будем искать документы, у которых вид операции "Продажа, комиссия".

Шаг 3: Выполнение запроса и получение выборки

После установки параметров выполняем запрос и получаем результат в виде выборки:


ВыборкаДокументы = Запрос.Выполнить().Выбрать();

Метод Выполнить() возвращает объект РезультатЗапроса, у которого мы вызываем метод Выбрать(). Этот метод возвращает объект ВыборкаИзТаблицы, который умеет перемещаться по записям с помощью метода Следующий().

Правильное получение объекта документа из выборки запроса

Это ключевой момент, где возникают наибольшие сложности. Как мы видели в предыдущих примерах, попытки получить объект напрямую из выборки (ВыборкаДокументы.ПолучитьОбъект) приводили к ошибкам.

При использовании ВыборкаИзТаблицы (полученной из запроса), каждый элемент выборки представляет собой строку результата запроса. В нашей выборке есть поле Ссылка. Чтобы получить объект документа, необходимо сначала обратиться к этому полю выборки, а затем уже у ссылки вызвать метод ПолучитьОбъект().

Правильный синтаксис внутри цикла обхода выборки будет таким:


Пока ВыборкаДокументы.Следующий() Цикл
    ДокОбъект = ВыборкаДокументы.Ссылка.ПолучитьОбъект(); // Ключевой момент!
    // ... дальнейшая работа с ДокОбъект
КонецЦикла;

Здесь ВыборкаДокументы.Ссылка обращается к полю "Ссылка" текущей записи выборки, которое содержит ссылку на документ. Затем у этой ссылки вызывается метод ПолучитьОбъект(), который возвращает уже сам объект документа, с которым можно работать (изменять реквизиты, записывать и т.д.).

Полный код для программного изменения вида операции

Теперь соберем все вместе в рабочую процедуру, которая будет изменять вид операции документов "Реализация товаров и услуг" с "Продажа, комиссия" на "Услуги" для заданного периода.


&НаСервере
Процедура ИзменитьВидОперацииРеализацииНаСервере(НачПериода, КонПериода)
    
    // 1. Создаем новый запрос
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |    РеализацияТоваровУслуг.Ссылка
        |ИЗ
        |    Документ.РеализацияТоваровУслуг КАК РеализацияТоваровУслуг
        |ГДЕ
        |    РеализацияТоваровУслуг.ВидОперации = &ИсходныйВидОперации
        |    И РеализацияТоваровУслуг.Дата МЕЖДУ &НачПериода И &КонПериода";
            
    // 2. Устанавливаем параметры запроса
    Запрос.УстановитьПараметр("ИсходныйВидОперации", Перечисления.ВидыОперацийРеализацияТоваров.ПродажаКомиссия);
    Запрос.УстановитьПараметр("НачПериода", НачалоДня(НачПериода));
    Запрос.УстановитьПараметр("КонПериода", КонецДня(КонПериода));
    
    // 3. Выполняем запрос и получаем выборку
    ВыборкаДокументы = Запрос.Выполнить().Выбрать();
    
    // 4. Обходим выборку и изменяем документы
    Пока ВыборкаДокументы.Следующий() Цикл
        // Получаем объект документа по его ссылке
        ДокОбъект = ВыборкаДокументы.Ссылка.ПолучитьОбъект();
        
        Если ДокОбъект.ВидОперации <> Перечисления.ВидыОперацийРеализацияТоваров.Услуги Тогда
            // Изменяем вид операции на "Услуги"
            ДокОбъект.ВидОперации = Перечисления.ВидыОперацийРеализацияТоваров.Услуги;
            
            Попытка
                // Записываем измененный документ
                ДокОбъект.Записать(РежимЗаписиДокумента.Проведение); // Важно: перепроводим документ
                Сообщить("Документ " + ДокОбъект.Номер + " от " + ДокОбъект.Дата + " успешно изменен и проведен. Новая версия: " + ДокОбъект.ВерсияДанных);
            Исключение
                Сообщить("Ошибка при записи документа " + ДокОбъект.Номер + " от " + ДокОбъект.Дата + ": " + ОписаниеОшибки());
            КонецПопытки;
        КонецЕсли;
    КонецЦикла;
    
    Сообщить("Обработка документов завершена.");
    
КонецПроцедуры

Данная процедура должна вызываться, например, из формы обработки, где пользователь задает период и запускает команду. Переменные НачПериода и КонПериода должны быть переданы в процедуру.

Важные моменты в коде:

Дополнительные рекомендации при массовом изменении документов

Массовое программное изменение документов — это ответственная операция. Рассмотрим дополнительные рекомендации, которые помогут избежать непредвиденных проблем:

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

  2. Резервное копирование: Всегда, без исключений, создавайте резервную копию информационной базы перед выполнением любых массовых программных изменений. Это ваша страховка на случай непредвиденных проблем.

  3. Тестирование: Никогда не запускайте код на продуктивной базе сразу. Сначала протестируйте его на тестовой базе данных, которая является копией реальных документов. Убедитесь в корректности изменений, проверьте движения по регистрам, сформируйте отчеты.

  4. Стандартные средства 1С: Для массового изменения реквизитов, включая вид операции, в типовых конфигурациях 1С существуют стандартные инструменты, такие как "Групповое изменение реквизитов" или "Групповая обработка документов и справочников". Эти обработки позволяют выполнять массовые изменения без написания кода и часто имеют дополнительные проверки. Изучите возможность использования этих инструментов перед написанием собственного кода.

  5. Исправление в закрытом периоде: Если изменения касаются документов в уже закрытом периоде, это может потребовать особого подхода. В некоторых конфигурациях 1С предусмотрена возможность ввода исправительных документов или сторно в текущем периоде для корректировки движений прошлых периодов. Вносить изменения непосредственно в закрытые периоды следует с большой осторожностью и пониманием всех бухгалтерских и налоговых последствий. Возможно, потребуется пересдача отчетности.

  6. Логирование: При программном изменении большого количества документов полезно вести логирование изменений. Это может быть запись в текстовый файл, регистр сведений или вывод сообщений с деталями о том, какие документы были изменены, какие были исходные значения, какие новые, и с каким результатом.

Кратко о перечислениях в 1С

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

Надеемся, что это подробное руководство поможет вам успешно справиться с задачей программного изменения вида операции документов "Реализация товаров и услуг" в 1С.

← На главную