Как корректно заполнить "Дату реализации" в документе "Отчет о розничных продажах (возврат)" в 1С:Бухгалтерии 3.0 при обмене из 1С:Розницы?

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

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

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

Почему "Дата реализации" так важна для возвратов?

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

  1. Определение себестоимости: Главная причина, по которой требуется дата реализации, — это возможность определить ту себестоимость, по которой товар был продан изначально. При возврате необходимо "вернуть" именно эту себестоимость. Если по одному и тому же товару было несколько продаж по разным ценам и, соответственно, разной себестоимости, то некорректно выбранная дата приведет к искажению финансовых результатов.
  2. Учет НДС: Отсутствие "Даты реализации" может привести к тому, что не будут заполняться необходимые регистры для учета НДС, такие как "НДС покупки" и "НДС предъявленный". Это, в свою очередь, чревато ошибками в декларации по НДС и проблемами при налоговых проверках.
  3. Партионный учет: В системах с партионным учетом "Дата реализации" помогает связать возврат с конкретной партией товара, что крайне важно для правильного формирования движений по счетам учета ТМЦ.

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

Анализ типового обмена между 1С:Розницей и 1С:Бухгалтерией 3.0

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

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

  1. Предполагаемая логика: Мы обнаружили, что в конфигурации 1С:Розница в правилах обмена (например, в макете узла "ОбменРозницаБухгалтерияПредприятия30") действительно существует логика, которая пытается извлекать "ДатуПродажи" из документа "ЧекККМ.Товары" для возвратов. Эта логика предполагает "хитрое разворачивание" от товара к чеку возврата, затем к чеку продажи, и даже группировку данных.
  2. Реальность типового обмена через EnterpriseData: Однако, как показывает практика и углубленный анализ, обмен между 1С:Розницей и 1С:Бухгалтерией 3.0 в современных реалиях часто осуществляется не через "классические" правила КД2, а через универсальный формат обмена EnterpriseData (ED), используя план обмена СинхронизацияДанныхЧерезУниверсальныйФормат. И именно в этом универсальном формате обмена необходимая логика по передаче "Даты реализации" для возвратов не день-в-день типовыми средствами 1С не реализована или реализована не полностью. Поэтому колонка в БП3 остается пустой.

Приведем пример того, как могла бы выглядеть выборка данных в Рознице, если бы она полностью передавалась в БП3 для возвратов (фрагмент кода из типовых правил, который не попадает в ED для данного сценария):


|ВЫБРАТЬ
|    ЧекККМТовары.Номенклатура КАК Номенклатура,
|    ЧекККМТовары.Характеристика КАК Характеристика,
|    СУММА(ЧекККМТовары.Количество) КАК Количество,
|    ЧекККМТовары.Цена КАК Цена,
|    СУММА(ЧекККМТовары.Сумма) КАК Сумма,
|    ЧекККМТовары.СтавкаНДС КАК СтавкаНДС,
|    СУММА(ЧекККМТовары.СуммаНДС) КАК СуммаНДС,
|    ЧекККМ.ДатаПродажи КАК ДатаРеализации,
|    ЧекККМ.НомерЧекаККМ КАК НомерФискальногоЧека,
|    ВЫБОР
|        КОГДА &ПередаватьЦеныХарактеристик
|            ТОГДА ВЫБОР
|                    КОГДА ЧекККМТовары.Характеристика = ЗНАЧЕНИЕ(Справочник.ХарактеристикиНоменклатуры.ПустаяСсылка)
|                        ТОГДА ЛОЖЬ
|                    ИНАЧЕ ИСТИНА
|                КОНЕЦ
|        ИНАЧЕ ЛОЖЬ
|    КОНЕЦ КАК ПередатьИсходящиеДанные,
|    ВЫБОР
|        КОГДА СпрНоменклатура.СтранаПроисхождения = ЗНАЧЕНИЕ(Справочник.СтраныМира.ПустаяСсылка)
|            ТОГДА ЗНАЧЕНИЕ(Справочник.СтраныМира.РОССИЯ)
|        ИНАЧЕ СпрНоменклатура.СтранаПроисхождения
|    КОНЕЦ КАК СтранаПроисхождения
|ИЗ
|    Документ.ЧекККМ.Товары КАК ЧекККМТовары
|        ВНУТРЕННЕЕ СОЕДИНЕНИЕ (ВЫБРАТЬ РАЗЛИЧНЫЕ
|            Док.Ссылка КАК Ссылка,
|            Док.ВидОперации КАК ВидОперации,
|            Док.ДатаПродажи,
|            Док.НомерЧекаККМ
|        ИЗ
|            ТаблицаПромежуточная КАК Док
|        ГДЕ
|            Док.ЭтоВозвратПослеЗакрытияСмены) КАК ЧекККМ
|        ПО ЧекККМТовары.Ссылка = ЧекККМ.Ссылка
|        ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Номенклатура КАК СпрНоменклатура
|        ПО (СпрНоменклатура.Ссылка = ЧекККМТовары.Номенклатура)
|ГДЕ
|    ЧекККМТовары.Ссылка.ОтчетОРозничныхПродажах = &Ссылка
|    И СпрНоменклатура.ТипНоменклатуры = ЗНАЧЕНИЕ(Перечисление.ТипыНоменклатуры.Товар)
|
|СГРУППИРОВАТЬ ПО
|    ЧекККМТовары.Номенклатура,
|    ЧекККМТовары.Характеристика,
|    ЧекККМТовары.Цена,
|    ЧекККМТовары.СтавкаНДС,
|    ЧекККМ.ДатаПродажи,
|    ЧекККМ.НомерЧекаККМ,
|    ВЫБОР
|        КОГДА СпрНоменклатура.СтранаПроисхождения = ЗНАЧЕНИЕ(Справочник.СтраныМира.ПустаяСсылка)
|            ТОГДА ЗНАЧЕНИЕ(Справочник.СтраныМира.РОССИЯ)
|        ИНАЧЕ СпрНоменклатура.СтранаПроисхождения
|    КОНЕЦ
|;

Данный код ясно демонстрирует намерение 1С связывать возвращаемые товары с их "ДатойПродажи". Однако, поскольку он не срабатывает через используемый механизм обмена, мы вынуждены искать обходные пути.

Подходы к решению проблемы

Для решения описанной проблемы мы можем рассмотреть несколько подходов, каждый из которых имеет свои преимущества и недостатки.

Решение 1: Доработка правил обмена EnterpriseData

Самый "правильный" и системный подход — это доработка правил обмена, использующих формат EnterpriseData. Этот метод потребует квалифицированного программиста, разбирающегося в механизмах 1С:Конвертация Данных 3.0 (КД3) и структуре EnterpriseData. При реализации подобных доработок будет полезен инструмент для отладки обмена через универсальный формат и внешних обработок.

  1. Анализ текущих правил: Сначала необходимо проанализировать текущие правила обмена между 1С:Розницей и БП3, чтобы понять, на каком этапе теряется "Дата реализации".
  2. Добавление логики: В правила обмена потребуется внести изменения, чтобы для строк возврата в ОРП происходило следующее:
    • Для каждой возвращаемой номенклатуры с характеристикой (если есть) находим соответствующий "ЧекККМ" (продажи).
    • Из этого "ЧекККМ" извлекаем ЧекККМ.ДатаПродажи.
    • Эту дату передаем в колонку "Дата реализации" в табличной части "Возвраты" документа ОРП в БП3.
  3. Учет сложностей: Следует учитывать, что один и тот же товар в одном возврате мог быть продан по разным чекам в разные даты. В таком случае, возможно, потребуется разбивать одну строку возврата ОРП на несколько строк в БП3, каждая со своей "Датой реализации". Это значительно усложняет доработку.

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

Решение 2: Разработка внешней обработки для автоматического заполнения "Даты реализации" в БП3

Этот подход является наиболее реалистичным "костылем", но требует глубокого понимания внутренних механизмов 1С:Бухгалтерии 3.0, особенно модуля УчетТоваров, который отвечает за контроль и расчет себестоимости. Наша задача — не просто подставить любую дату, а такую, которая позволит документу корректно провестись, и себестоимость будет рассчитана верно.

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

Шаг 1: Определение подходящих продаж

Для каждой строки возврата в ОРП необходимо найти подходящие документы реализации. Мы будем осуществлять поиск продаж по соответствующей номенклатуре, характеристике, организации и, что важно, складу.

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

В этом случае обработка должна будет определить, что 16 штук возвращаются из партии, проданной 1 февраля. "Дата реализации" для этой строки ОРП будет установлена как "1 февраля".

Однако ситуация может быть сложнее:

Здесь нам уже не хватает остатка из продажи от 1 февраля (осталось 20 - 16 = 4 штуки). Следовательно, эти 15 штук нужно "разбить":

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

Шаг 2: Учет строгих контролей 1С:Бухгалтерии

1С:Бухгалтерия 3.0 имеет очень строгие механизмы контроля при проведении документов, связанных с учетом товаров, особенно при возвратах. Наша обработка должна быть спроектирована таким образом, чтобы успешно проходить эти контроли.

Ключевая функция, задействованная в этом процессе, находится в общем модуле УчетТоваров и называется ПодготовитьТаблицуВозвращенныеСписанныеТовары. Проанализируем ее основные моменты:


Функция ПодготовитьТаблицуВозвращенныеСписанныеТовары(ТаблицаТовары, ТаблицаСчетаУчетаТоваров, ТаблицаСписокНоменклатуры, ТаблицаРеквизиты, Отказ) Экспорт
    Если Не ЗначениеЗаполнено(ТаблицаТовары)
    Или Не ЗначениеЗаполнено(ТаблицаРеквизиты) Тогда
        Возврат Неопределено;
    КонецЕсли;

    ТаблицаРезультата = ПолучитьПустуюТаблицуСписанныеТовары();

    Реквизиты = ТаблицаРеквизиты[0];

    Если Не Реквизиты.УказанДокументОтгрузки
    Или Не ЗначениеЗаполнено(ТаблицаСчетаУчетаТоваров) Тогда
        ОбщегоНазначенияБПВызовСервера.ЗагрузитьВТаблицуЗначений(ТаблицаТовары, ТаблицаРезультата);
        Возврат ТаблицаРезультата;
    КонецЕсли;

    // ... Пропуск части кода, связанного с определением счетов учета ...

    ДатаДокументаРеализации = Реквизиты.ДатаДокументаРеализации;

    Если НачалоДня(Реквизиты.Период) < НачалоДня(ДатаДокументаРеализации) Тогда

            ТекстСообщения = НСтр("ru = 'Возврат по документу ""%1"" не может быть раньше %2 г.'");
            // ... Формирование сообщения об ошибке ...
            Отказ = Истина;
        ОбщегоНазначенияБПВызовСервера.ЗагрузитьВТаблицуЗначений(ТаблицаТовары, ТаблицаРезультата);
        Возврат ТаблицаРезультата;

    Иначе

        ВозвратПрошлогоМесяца = НачалоМесяца(Реквизиты.Период) <> НачалоМесяца(ДатаДокументаРеализации);

    КонецЕсли; 

    // ... Пропуск части кода, связанного со складами и подразделениями ...

    Если ВозвратПрошлогоМесяца Тогда
        ТекстЗапроса = ТекстЗапросаВозвращенныеСписанныеТоварыПрошлогоМесяца(...);
    Иначе
        ТекстЗапроса = ТекстЗапросаВозвращенныеСписанныеТоварыТекущегоМесяца(...);
    КонецЕсли;

    ТекстЗапроса = ТекстЗапроса + 
    "ВЫБРАТЬ
    |    ВТ_СписанныеТовары.Номенклатура,
    |    ВТ_СписанныеТовары.Партия,
    |    ВТ_СписанныеТовары.СчетУчета,
    |    ЕСТЬNULL(РеквизитыДокументаПартии.ДатаРегистратора, ДАТАВРЕМЯ(1, 1, 1)) КАК ДатаПартии,
    |    СУММА(ВТ_СписанныеТовары.Сумма) КАК Сумма,
    |    // ... другие суммы ...
    |    СУММА(ВТ_СписанныеТовары.Количество) КАК Количество,
    |    СУММА(ВТ_СписанныеТовары.КоличествоОтгружено) КАК КоличествоОтгружено // Остаток (количество) который можно вернуть по конкретной реализации
    |ИЗ
    |    ВТ_СписанныеТовары КАК ВТ_СписанныеТовары
    |    // ... соединения ...
    |ГДЕ 
    |    ВТ_СписанныеТовары.Номенклатура В (&Товары)
    |СГРУППИРОВАТЬ ПО
    |    // ... поля группировки ...
    |ИМЕЮЩИЕ
    |    СУММА(ВТ_СписанныеТовары.Количество) > 0
    |УПОРЯДОЧИТЬ ПО
    |    ВТ_СписанныеТовары.Номенклатура,
    |    ДатаПартии УБЫВ";
    // ... Установка параметров запроса ...

    ТаблицаОтгрузок = Запрос.Выполнить().Выгрузить();

    Для каждого СтрокаВозврата Из Параметры.ТаблицаТовары Цикл
        КоличествоНеПодобраноПартии = СтрокаВозврата.Количество;
        ОтгруженныеПартии = ТаблицаОтгрузок.НайтиСтроки(Новый Структура("Номенклатура, СчетУчета", СтрокаВозврата.Номенклатура, СтрокаВозврата.СчетУчета));
        Для каждого СтрокаОтгрузки Из ОтгруженныеПартии Цикл

            Если СтрокаОтгрузки.КоличествоОтгружено = 0 Тогда
                Продолжить;
            КонецЕсли; 

            НоваяСтрока = ТаблицаРезультата.Добавить();
            ЗаполнитьЗначенияСвойств(НоваяСтрока, СтрокаВозврата);
            НоваяСтрока.Партия = СтрокаОтгрузки.Партия;
            НоваяСтрока.Сделка = Реквизиты.Сделка;

            КоличествоВозвращено = Мин(КоличествоНеПодобраноПартии, СтрокаОтгрузки.КоличествоОтгружено);
            Если КоличествоВозвращено >= СтрокаОтгрузки.Количество Тогда
                // Полный возврат всей партии
                НоваяСтрока.Количество           = СтрокаОтгрузки.Количество;
                НоваяСтрока.СуммаСписания        = СтрокаОтгрузки.Сумма;
                // ... другие суммы ...
            Иначе
                // Частичный возврат партии
                НоваяСтрока.Количество           = КоличествоВозвращено;
                Коэфф                            = КоличествоВозвращено / СтрокаОтгрузки.Количество;
                НоваяСтрова.СуммаСписания        = Окр(СтрокаОтгрузки.Сумма  * Коэфф, 2);
                // ... другие суммы ...
            КонецЕсли;

            КоличествоНеПодобраноПартии = КоличествоНеПодобраноПартии - НоваяСтрока.Количество;

            СтрокаОтгрузки.Количество             = СтрокаОтгрузки.Количество - НоваяСтрока.Количество;
            СтрокаОтгрузки.КоличествоОтгружено    = СтрокаОтгрузки.КоличествоОтгружено - НоваяСтрока.Количество;
            // ... обновление сумм ...

            Если КоличествоНеПодобраноПартии = 0 Тогда
                Прервать;
            КонецЕсли;
        КонецЦикла;
        Если КоличествоНеПодобраноПартии > 0 Тогда
            ТекстСообщения = НСтр("ru = 'Документом ""%1"" было реализовано ""%2"" на ""%3"" ед. меньше, чем возвращается.'");
            // ... Формирование сообщения об ошибке ...
            Отказ = Истина;
        КонецЕсли;
    КонецЦикла;
    Возврат ТаблицаРезультата;
КонецФункции

Из анализа этого кода мы видим следующие важные контроли и логику:

  1. Контроль даты: Система проверяет, чтобы дата документа возврата (Реквизиты.Период) не была раньше "Даты реализации" (ДатаДокументаРеализации). Если это условие нарушается, документ не проводится.
  2. Остаток количества: Запрос получает данные о ранее отгруженном количестве (КоличествоОтгружено), которое еще может быть возвращено по конкретной реализации (партии). Это означает, что если по одной реализации было продано 20 штук, а уже 16 из них вернули, то максимально можно вернуть еще только 4 штуки из этой же реализации.
  3. Разбиение по партиям: Цикл по ОтгруженныеПартии пытается распределить возвращаемое количество по имеющимся партиям (реализациям) в порядке убывания даты (ДатаПартии УБЫВ). Если количество возврата больше, чем остаток по текущей партии, остаток списывается полностью, и поиск продолжается по следующей партии.
  4. Сообщение об ошибке: Если после перебора всех возможных партий остается неподобранное количество (КоличествоНеПодобраноПартии > 0), выдается сообщение об ошибке, что реализовано меньше, чем возвращается.

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

Шаг 3: Учет склада отгрузки

Еще одно важное открытие, сделанное при практической реализации, касается учета складов. Система 1С, особенно при ведении суммового учета по складам, строго контролирует соответствие склада в документе возврата складу, указанному в документе первоначальной реализации.

В коде это видно по условию ИспользоватьОтборПоСкладуОтгрузки = ВедетсяСуммовойУчетПоСкладам И ЕстьСкладОтгрузки. Это означает, что если в ОРП возврата указан Склад А, а товар был продан со Склада Б, то документ не проведется, даже если на Складе А и Складе Б достаточное количество товара и есть подходящие даты реализации. Такой подход 1С, хотя и обеспечивает строгость учета, может создавать проблемы для клиентоориентированных компаний, которые могут принимать возвраты на любой удобный для клиента склад.

Нашей обработке необходимо учитывать этот аспект и при поиске документов реализации фильтровать их не только по номенклатуре и дате, но и по складу.

Решение 3: Изменение процесса оформления возвратов в 1С:Рознице

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

  1. Преимущества: Документ "Возврат товаров от клиента" может быть введен на основании документа "Реализация (акт, накладная)" или "Отчет о розничных продажах" (если он уже проведен). Если "Возврат товаров от клиента" вводится на основании документа реализации, то система автоматически подтягивает себестоимость и, в большинстве случаев, дату реализации.
  2. Недостатки:
    • Переобучение кассиров: Этот метод требует значительных изменений в повседневной работе кассиров и переобучения персонала.
    • Изменение РМК: Возможно, потребуются доработки интерфейса Рабочего Места Кассира (РМК) в 1С:Рознице, чтобы упростить оформление "Возвратов товаров от клиента" вместо чеков возврата.
    • Пробитие по кассе: "Возврат товаров от клиента" обычно сопровождается "Расходным кассовым ордером" и требует пробития чека на возврат по кассе.
    • Сложность обмена: Возможно, потребуются новые настройки обмена для корректной передачи этих документов в БП3, если текущие правила не предусматривают их синхронизацию.

Хотя на первый взгляд этот метод кажется простым, его внедрение сопряжено с серьезными организационными и техническими изменениями, которые пользователи форума часто отвергают из-за их масштаба ради "вшивой себестоимости".

Заключение

Проблема некорректного заполнения "Даты реализации" в ОРП (возврат) при обмене из 1С:Розницы в 1С:Бухгалтерию 3.0 является достаточно распространенной и не имеет простого типового решения "из коробки" в текущих механизмах обмена EnterpriseData. Мы рассмотрели три основных подхода к ее решению:

  1. Доработка правил обмена EnterpriseData.
  2. Разработка внешней обработки для автоматического заполнения "Даты реализации" в БП3.
  3. Изменение бизнес-процесса оформления возвратов в 1С:Рознице.

Наиболее прагматичным и часто выбираемым путем является разработка внешней обработки, которая умеет искать подходящие даты реализации, распределять возвращаемое количество по соответствующим продажам (партиям) и, что критически важно, проходит все строгие контроли 1С:Бухгалтерии 3.0, включая проверку склада отгрузки. Это требует глубокого анализа конфигураций и детальной проработки логики.

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

← На главную