Почему Z-отчет Frontol не совпадает с «Отчетом о розничных продажах» 1С при возвратах товаров со скидкой, и как это исправить?

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

Многие компании, использующие связку кассового программного обеспечения Frontol и учетной системы 1С, сталкиваются с проблемой расхождений между суммами Z-отчета и документом «Отчет о розничных продажах» в 1С. Эти расхождения могут достигать существенных значений, до нескольких тысяч рублей, и часто связаны с особенностями обработки возвратов товаров, особенно тех, которые были проданы со скидками. Давайте подробно разберем эту проблему и предложим пути ее решения.

Суть проблемы: несовпадение Z-отчета и «Отчета о розничных продажах» в 1С

Начнем с того, что Z-отчет, формируемый кассовым аппаратом через Frontol, как правило, отражает фактическое движение денежных средств через кассу: приход наличных, возврат прихода, безналичные оплаты и возвраты. Суммы в Z-отчете являются корректными и совпадают с данными Frontol. Проблема возникает на этапе загрузки этих данных в 1С и формировании документа ОтчетОРозничныхПродажах.

Рассмотрим несколько типовых ситуаций, которые помогут нам понять, почему возникают эти расхождения:

  1. Ситуация 1: Продажи без возвратов в течение дня

    Предположим, в течение дня через Frontol были совершены следующие продажи:

    • Футболка 1: 1 шт. по 100 руб. = 100 руб.
    • Футболка 2: 1 шт. по 200 руб. = 200 руб.

    После закрытия смены:

    • Z-отчет: Приход наличными – 300 руб., Возврат прихода – 0 руб., Выручка – 300 руб.
    • «Отчет о розничных продажах» в 1С:
      1. Футболка 1: 1 шт. по 100 руб. = 100 руб.
      2. Футболка 2: 1 шт. по 200 руб. = 200 руб.

    Сумма в 1С: 300 руб. В этом случае все совпадает, проблем нет.

  2. Ситуация 2: Продажа и возврат одного и того же товара по одинаковой цене в течение дня

    В течение дня были продажи:

    • Футболка 1: 1 шт. по 100 руб. = 100 руб.
    • Футболка 2: 1 шт. по 200 руб. = 200 руб.

    Затем покупатель, который ранее (возможно, даже в тот же день) купил «Футболку 1» за 100 руб., вернул ее:

    • Возврат «Футболка 1»: 1 шт. по 100 руб. = 100 руб.

    После закрытия смены:

    • Z-отчет: Приход наличными – 300 руб., Возврат прихода – 100 руб., Выручка – 200 руб.
    • «Отчет о розничных продажах» в 1С:
      1. Футболка 2: 1 шт. по 200 руб. = 200 руб.

    Сумма в 1С: 200 руб. В данной ситуации 1С «выбросила» позицию «Футболка 1» из отчета, поскольку в течение дня была и продажа, и возврат такой же позиции по одинаковой цене. Количественно и суммарно учет корректен, так как +100 руб. за продажу и -100 руб. за возврат дают 0. Расхождений нет.

  3. Ситуация 3: Продажа и возврат одного и того же товара, но с разницей в цене (ключевая проблема)

    В течение дня были продажи:

    • Футболка 1: 1 шт. по 100 руб. = 100 руб.
    • Футболка 2: 1 шт. по 200 руб. = 200 руб.

    Затем клиент, который ранее (например, вчера) купил «Футболку 1» со скидкой 5%, решил ее вернуть. Возврат был оформлен на фактическую сумму продажи:

    • Возврат «Футболка 1»: 1 шт. по 95 руб. = 95 руб.

    После закрытия смены:

    • Z-отчет: Приход наличными – 300 руб., Возврат прихода – 95 руб., Выручка – 205 руб.
    • «Отчет о розничных продажах» в 1С:
      1. Футболка 2: 1 шт. по 200 руб. = 200 руб.

    Сумма в 1С: 200 руб.
    И вот здесь мы видим расхождение! Z-отчет показывает выручку 205 руб., а в 1С прилетело только списание товара «Футболка 2» за 200 руб. Как и в ситуации 2, 1С «выбросила» позицию «Футболка 1» из отчета, потому что видит и продажу, и возврат одной и той же номенклатуры. Однако, в отличие от ситуации 2, суммы продажи (100 руб.) и возврата (95 руб.) не совпадают. Из-за этого потерялись 5 руб., и отчет 1С не соответствует Z-отчету.

Почему 1С так поступает? Похоже, что стандартная логика загрузки данных или формирования ОтчетаОРозничныхПродажах стремится показать «чистые» продажи по номенклатуре за период. Если система видит, что одна и та же позиция была продана и возвращена, она может автоматически исключать эти строки, считая, что они компенсировали друг друга. Это удобно для количественного учета, но ошибочно для суммового, если цены не совпали. В результате, фактическая выручка по кассе (отраженная в Z-отчете) не совпадает с выручкой, отраженной в 1С.

Анализируем причины расхождений глубже

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

  1. «Схлопывание» позиций по номенклатуре: Основная причина кроется в алгоритмах обработки данных при формировании ОтчетаОРозничныхПродажах. 1С может быть настроена на то, чтобы группировать операции по одной и той же номенклатуре. Если в рамках одной кассовой смены или одного дня присутствуют как продажа, так и возврат одной и той же позиции, система пытается их «схлопнуть» или «занулить». Это поведение вполне логично, когда суммы продажи и возврата идеально совпадают. Однако, когда они различаются (например, из-за ранее примененной скидки), такое «схлопывание» приводит к потере разницы.
  2. Отсутствие привязки возврата к исходному чеку продажи: Часто при загрузке данных из Frontol в 1С передается сводная информация или данные о чеках без глубокой детализации и однозначной привязки возврата к конкретному чеку продажи. В такой ситуации 1С не может автоматически определить первоначальную цену со скидкой, по которой был продан товар, и может использовать текущую цену номенклатуры или цену, указанную в документе возврата из Frontol, который также мог не содержать полной информации об исходной скидке.
  3. Разная логика обработки скидок: Системы Frontol и 1С могут по-разному обрабатывать и передавать информацию о скидках. Если скидка была применена в Frontol, но в 1С при возврате не удается сопоставить этот возврат с конкретной продажей, 1С может либо проигнорировать скидку, либо применить свою логику расчета, что приводит к разнице в ценах.

Предлагаемое решение: корректировка логики загрузки данных в 1С

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

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

  1. Определяем место для модификации

    Нам необходимо найти обработчик или модуль, который отвечает за загрузку чеков из Frontol и формирование документа ОтчетОРозничныхПродажах в вашей конфигурации 1С. Обычно это может быть:

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

    Чаще всего логика обработки находится в процедуре, которая перебирает строки чеков из файла выгрузки (например, формата АТОЛ или другого). Вам нужно будет использовать конфигуратор 1С для поиска этих участков кода.

  2. Анализируем логику формирования строк отчета

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

  3. Внедряем условное исключение позиций

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

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

    1. Если продажа и возврат одной и той же номенклатуры произошли в течение одной смены (или отчетного периода) и их суммы полностью совпадают: В этом случае, действительно, можно «схлопнуть» эти позиции, то есть не добавлять их в отчет, так как они взаимно компенсируют друг друга как по количеству, так и по сумме.
    2. Если продажа и возврат одной и той же номенклатуры произошли в течение одной смены (или отчетного периода), но их суммы РАЗЛИЧАЮТСЯ: В этом критическом случае обе строки – продажа (с положительной суммой) и возврат (с отрицательной суммой) – должны быть добавлены в ОтчетОРозничныхПродажах. Это обеспечит корректное суммирование и отражение фактической выручки, которая будет соответствовать Z-отчету. Система не должна их исключать.

    Это позволит сохранить разницу в суммах, возникающую из-за скидок или других ценовых корректировок, и корректно отразить ее в итоговой выручке 1С.

  4. Примерная логика модификации (псевдокод)

    Представим, что у нас есть структура данных ДанныеЧековИзFrontol, содержащая все операции за смену (продажи и возвраты). Нам нужно пройтись по ним и сформировать ОтчетОРозничныхПродажах.

    
    // Инициализируем временную структуру для хранения и обработки строк
    // Это может быть ТаблицаЗначений или Соответствие, где ключ - Номенклатура
    // Значение - структура с общим количеством, суммой и флагом, что были и продажи и возвраты
    ВременныеСтрокиОтчета = Новый Соответствие; 
    
    Для Каждой СтрокиЧека Из ДанныеЧековИзFrontol Цикл
        НоменклатураТекущейСтроки = СтрокаЧека.Номенклатура;
        СуммаТекущейСтроки = СтрокаЧека.Сумма;
        КоличествоТекущейСтроки = СтрокаЧека.Количество;
        ТипОперацииТекущейСтроки = СтрокаЧека.ТипОперации; // "Продажа" или "Возврат"
    
        Если НЕ ВременныеСтрокиОтчета.Содержит(НоменклатураТекущейСтроки) Тогда
            // Если номенклатура встречается впервые, добавляем ее
            ВременныеСтрокиОтчета.Вставить(НоменклатураТекущейСтроки, Новый Структура(
                "Количество", 0, 
                "Сумма", 0, 
                "БылаПродажа", Ложь, 
                "БылВозврат", Ложь,
                "ИсходныеСтроки", Новый Массив() // Для хранения исходных строк, если суммы не совпадут
            ));
        КонецЕсли;
    
        ТекущиеДанныеНоменклатуры = ВременныеСтрокиОтчета.Получить(НоменклатураТекущейСтроки);
    
        Если ТипОперацииТекущейСтроки = "Продажа" Тогда
            ТекущиеДанныеНоменклатуры.Количество = ТекущиеДанныеНоменклатуры.Количество + КоличествоТекущейСтроки;
            ТекущиеДанныеНоменклатуры.Сумма = ТекущиеДанныеНоменклатуры.Сумма + СуммаТекущейСтроки;
            ТекущиеДанныеНоменклатуры.БылаПродажа = Истина;
        ИначеЕсли ТипОперацииТекущейСтроки = "Возврат" Тогда
            ТекущиеДанныеНоменклатуры.Количество = ТекущиеДанныеНоменклатуры.Количество - КоличествоТекущейСтроки;
            ТекущиеДанныеНоменклатуры.Сумма = ТекущиеДанныеНоменклатуры.Сумма - СуммаТекущейСтроки;
            ТекущиеДанныеНоменклатуры.БылВозврат = Истина;
        КонецЕсли;
    
        // Добавляем исходную строку, если потом придется выводить все без схлопывания
        ТекущиеДанныеНоменклатуры.ИсходныеСтроки.Добавить(СтрокаЧека);
    
        ВременныеСтрокиОтчета.Вставить(НоменклатураТекущейСтроки, ТекущиеДанныеНоменклатуры);
    КонецЦикла;
    
    // Теперь формируем табличную часть ОтчетаОРозничныхПродажах на основе ВременныеСтрокиОтчета
    Для Каждого ЭлементСоответствия Из ВременныеСтрокиОтчета Цикл
        Номенклатура = ЭлементСоответствия.Ключ;
        ДанныеНоменклатуры = ЭлементСоответствия.Значение;
    
        Если ДанныеНоменклатуры.БылаПродажа И ДанныеНоменклатуры.БылВозврат И ДанныеНоменклатуры.Сумма = 0 Тогда
            // Продажа и возврат по одной номенклатуре, суммы точно скомпенсировали друг друга,
            // итоговая сумма 0. Можно не добавлять в отчет.
            Продолжить; 
        Иначе
            // Либо не было возврата/продажи, либо суммы не скомпенсировались.
            // В этом случае добавляем все исходные строки по этой номенклатуре в отчет.
            // Каждая продажа как положительная строка, каждый возврат как отрицательная.
            Для Каждой ИсходнаяСтрока Из ДанныеНоменклатуры.ИсходныеСтроки Цикл
                СтрокаТабличнойЧасти = ОтчетОРозничныхПродажах.Товары.Добавить();
                СтрокаТабличнойЧасти.Номенклатура = ИсходнаяСтрока.Номенклатура;
                СтрокаТабличнойЧасти.Количество = ИсходнаяСтрока.Количество * (Если ИсходнаяСтрока.ТипОперации = "Продажа" Тогда 1 Иначе -1 КонецЕсли);
                СтрокаТабличнойЧасти.Сумма = ИсходнаяСтрока.Сумма * (Если ИсходнаяСтрока.ТипОперации = "Продажа" Тогда 1 Иначе -1 КонецЕсли);
                // Дополнительные поля, если необходимо (Цена, СтавкаНДС и т.д.)
            КонецЦикла;
        КонецЕсли;
    КонецЦикла;
    

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

Дополнительные рекомендации и лучшие практики

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

  1. Настройка обмена с учетом скидок

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

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

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

  3. Учет себестоимости при возврате

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

  4. Тестирование изменений

    Любые изменения в логике обмена или формировании отчетов должны быть тщательно протестированы. Мы рекомендуем провести тестирование на тестовой базе данных, воспроизведя все возможные сценарии продаж и возвратов (с разными ценами, со скидками, возвраты в день продажи и в другие дни) и убедиться, что Z-отчеты Frontol и ОтчетыОРозничныхПродажах в 1С теперь совпадают.

  5. Версионность и конфигурация 1С

    Имейте в виду, что точные названия модулей, процедур и объектов 1С могут отличаться в зависимости от используемой конфигурации (1С:Розница, 1С:УправлениеТорговлей, 1С:КомплекснаяАвтоматизация, 1С:БухгалтерияПредприятия) и ее версии. При поиске участков для модификации всегда ориентируйтесь на актуальную документацию и структуру вашей информационной базы.

Заключение

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

← На главную