Многие компании, использующие связку кассового программного обеспечения Frontol и учетной системы 1С, сталкиваются с проблемой расхождений между суммами Z-отчета и документом «Отчет о розничных продажах» в 1С. Эти расхождения могут достигать существенных значений, до нескольких тысяч рублей, и часто связаны с особенностями обработки возвратов товаров, особенно тех, которые были проданы со скидками. Давайте подробно разберем эту проблему и предложим пути ее решения.
Начнем с того, что Z-отчет, формируемый кассовым аппаратом через Frontol, как правило, отражает фактическое движение денежных средств через кассу: приход наличных, возврат прихода, безналичные оплаты и возвраты. Суммы в Z-отчете являются корректными и совпадают с данными Frontol. Проблема возникает на этапе загрузки этих данных в 1С и формировании документа ОтчетОРозничныхПродажах.
Рассмотрим несколько типовых ситуаций, которые помогут нам понять, почему возникают эти расхождения:
Предположим, в течение дня через Frontol были совершены следующие продажи:
После закрытия смены:
Сумма в 1С: 300 руб. В этом случае все совпадает, проблем нет.
В течение дня были продажи:
Затем покупатель, который ранее (возможно, даже в тот же день) купил «Футболку 1» за 100 руб., вернул ее:
После закрытия смены:
Сумма в 1С: 200 руб. В данной ситуации 1С «выбросила» позицию «Футболка 1» из отчета, поскольку в течение дня была и продажа, и возврат такой же позиции по одинаковой цене. Количественно и суммарно учет корректен, так как +100 руб. за продажу и -100 руб. за возврат дают 0. Расхождений нет.
В течение дня были продажи:
Затем клиент, который ранее (например, вчера) купил «Футболку 1» со скидкой 5%, решил ее вернуть. Возврат был оформлен на фактическую сумму продажи:
После закрытия смены:
Сумма в 1С: 200 руб.
И вот здесь мы видим расхождение! Z-отчет показывает выручку 205 руб., а в 1С прилетело только списание товара «Футболка 2» за 200 руб. Как и в ситуации 2, 1С «выбросила» позицию «Футболка 1» из отчета, потому что видит и продажу, и возврат одной и той же номенклатуры. Однако, в отличие от ситуации 2, суммы продажи (100 руб.) и возврата (95 руб.) не совпадают. Из-за этого потерялись 5 руб., и отчет 1С не соответствует Z-отчету.
Почему 1С так поступает? Похоже, что стандартная логика загрузки данных или формирования ОтчетаОРозничныхПродажах стремится показать «чистые» продажи по номенклатуре за период. Если система видит, что одна и та же позиция была продана и возвращена, она может автоматически исключать эти строки, считая, что они компенсировали друг друга. Это удобно для количественного учета, но ошибочно для суммового, если цены не совпали. В результате, фактическая выручка по кассе (отраженная в Z-отчете) не совпадает с выручкой, отраженной в 1С.
Чтобы найти эффективное решение, нам необходимо глубже понять, почему 1С ведет себя таким образом:
ОтчетаОРозничныхПродажах. 1С может быть настроена на то, чтобы группировать операции по одной и той же номенклатуре. Если в рамках одной кассовой смены или одного дня присутствуют как продажа, так и возврат одной и той же позиции, система пытается их «схлопнуть» или «занулить». Это поведение вполне логично, когда суммы продажи и возврата идеально совпадают. Однако, когда они различаются (например, из-за ранее примененной скидки), такое «схлопывание» приводит к потере разницы.
Ключевым шагом для решения этой проблемы является изменение логики обработки данных, которые поступают из Frontol в 1С, чтобы предотвратить некорректное «схлопывание» позиций. Вместо того чтобы безусловно исключать совпадающие по номенклатуре продажи и возвраты, мы должны добавить условие проверки сумм.
Разберем по шагам, как можно реализовать данное решение:
Нам необходимо найти обработчик или модуль, который отвечает за загрузку чеков из Frontol и формирование документа ОтчетОРозничныхПродажах в вашей конфигурации 1С. Обычно это может быть:
ОбменДаннымиСРозницей, ЗагрузкаДанныхККМ).ОтчетОРозничныхПродажах, если формирование происходит напрямую при его создании.Чаще всего логика обработки находится в процедуре, которая перебирает строки чеков из файла выгрузки (например, формата АТОЛ или другого). Вам нужно будет использовать конфигуратор 1С для поиска этих участков кода.
Внутри найденного участка кода мы должны обнаружить место, где происходит добавление позиций в табличную часть Товары документа ОтчетОРозничныхПродажах. Мы также должны выяснить, как система обрабатывает возвраты — добавляет их как отдельные строки с отрицательными суммами/количествами, или пытается найти соответствующую продажу и скорректировать ее.
Основная идея модификации заключается в том, чтобы изменить условие, по которому 1С решает «выбросить» (исключить) строки продажи и возврата одной и той же номенклатуры. Вместо того чтобы исключать их только по совпадению номенклатуры, мы должны добавить проверку на совпадение сумм.
Мы должны стремиться к тому, чтобы система включала в ОтчетОРозничныхПродажах все операции (как продажи, так и возвраты) по каждой номенклатуре, но обрабатывала их следующим образом:
ОтчетОРозничныхПродажах. Это обеспечит корректное суммирование и отражение фактической выручки, которая будет соответствовать Z-отчету. Система не должна их исключать.Это позволит сохранить разницу в суммах, возникающую из-за скидок или других ценовых корректировок, и корректно отразить ее в итоговой выручке 1С.
Представим, что у нас есть структура данных ДанныеЧековИзFrontol, содержащая все операции за смену (продажи и возвраты). Нам нужно пройтись по ним и сформировать ОтчетОРозничныхПродажах.
// Инициализируем временную структуру для хранения и обработки строк
// Это может быть ТаблицаЗначений или Соответствие, где ключ - Номенклатура
// Значение - структура с общим количеством, суммой и флагом, что были и продажи и возвраты
ВременныеСтрокиОтчета = Новый Соответствие;
Для Каждой СтрокиЧека Из ДанныеЧековИзFrontol Цикл
НоменклатураТекущейСтроки = СтрокаЧека.Номенклатура;
СуммаТекущейСтроки = СтрокаЧека.Сумма;
КоличествоТекущейСтроки = СтрокаЧека.Количество;
ТипОперацииТекущейСтроки = СтрокаЧека.ТипОперации; // "Продажа" или "Возврат"
Если НЕ ВременныеСтрокиОтчета.Содержит(НоменклатураТекущейСтроки) Тогда
// Если номенклатура встречается впервые, добавляем ее
ВременныеСтрокиОтчета.Вставить(НоменклатураТекущейСтроки, Новый Структура(
"Количество", 0,
"Сумма", 0,
"БылаПродажа", Ложь,
"БылВозврат", Ложь,
"ИсходныеСтроки", Новый Массив() // Для хранения исходных строк, если суммы не совпадут
));
КонецЕсли;
ТекущиеДанныеНоменклатуры = ВременныеСтрокиОтчета.Получить(НоменклатураТекущейСтроки);
Если ТипОперацииТекущейСтроки = "Продажа" Тогда
ТекущиеДанныеНоменклатуры.Количество = ТекущиеДанныеНоменклатуры.Количество + КоличествоТекущейСтроки;
ТекущиеДанныеНоменклатуры.Сумма = ТекущиеДанныеНоменклатуры.Сумма + СуммаТекущейСтроки;
ТекущиеДанныеНоменклатуры.БылаПродажа = Истина;
ИначеЕсли ТипОперацииТекущейСтроки = "Возврат" Тогда
ТекущиеДанныеНоменклатуры.Количество = ТекущиеДанныеНоменклатуры.Количество - КоличествоТекущейСтроки;
ТекущиеДанныеНоменклатуры.Сумма = ТекущиеДанныеНоменклатуры.Сумма - СуммаТекущейСтроки;
ТекущиеДанныеНоменклатуры.БылВозврат = Истина;
КонецЕсли;
// Добавляем исходную строку, если потом придется выводить все без схлопывания
ТекущиеДанныеНоменклатуры.ИсходныеСтроки.Добавить(СтрокаЧека);
ВременныеСтрокиОтчета.Вставить(НоменклатураТекущейСтроки, ТекущиеДанныеНоменклатуры);
КонецЦикла;
// Теперь формируем табличную часть ОтчетаОРозничныхПродажах на основе ВременныеСтрокиОтчета
Для Каждого ЭлементСоответствия Из ВременныеСтрокиОтчета Цикл
Номенклатура = ЭлементСоответствия.Ключ;
ДанныеНоменклатуры = ЭлементСоответствия.Значение;
Если ДанныеНоменклатуры.БылаПродажа И ДанныеНоменклатуры.БылВозврат И ДанныеНоменклатуры.Сумма = 0 Тогда
// Продажа и возврат по одной номенклатуре, суммы точно скомпенсировали друг друга,
// итоговая сумма 0. Можно не добавлять в отчет.
Продолжить;
Иначе
// Либо не было возврата/продажи, либо суммы не скомпенсировались.
// В этом случае добавляем все исходные строки по этой номенклатуре в отчет.
// Каждая продажа как положительная строка, каждый возврат как отрицательная.
Для Каждой ИсходнаяСтрока Из ДанныеНоменклатуры.ИсходныеСтроки Цикл
СтрокаТабличнойЧасти = ОтчетОРозничныхПродажах.Товары.Добавить();
СтрокаТабличнойЧасти.Номенклатура = ИсходнаяСтрока.Номенклатура;
СтрокаТабличнойЧасти.Количество = ИсходнаяСтрока.Количество * (Если ИсходнаяСтрока.ТипОперации = "Продажа" Тогда 1 Иначе -1 КонецЕсли);
СтрокаТабличнойЧасти.Сумма = ИсходнаяСтрока.Сумма * (Если ИсходнаяСтрока.ТипОперации = "Продажа" Тогда 1 Иначе -1 КонецЕсли);
// Дополнительные поля, если необходимо (Цена, СтавкаНДС и т.д.)
КонецЦикла;
КонецЕсли;
КонецЦикла;
Этот псевдокод демонстрирует логику: сначала мы агрегируем все операции по номенклатуре. Если для номенклатуры были и продажи, и возвраты, и итоговая сумма этих операций равна нулю, тогда мы можем пропустить эти позиции. В противном случае, если сумма не равна нулю (то есть есть расхождение из-за скидок или других факторов), или если была только продажа/только возврат, мы добавляем все исходные строки в отчет, чтобы сохранить полную картину движения денег и товаров.
Для обеспечения максимальной точности и избежания подобных расхождений, мы также рекомендуем обратить внимание на следующие аспекты:
Убедитесь, что обмен между Frontol и 1С настроен таким образом, чтобы информация о скидках, применяемых в Frontol, корректно передавалась в 1С. В базовых настройках обмена может отсутствовать полная детализация скидок, что приводит к сложностям при возвратах. Мы рекомендуем использовать расширенные модули обмена или дорабатывать стандартные, чтобы:
В некоторых случаях (например, когда возврат происходит не в день покупки, или требуется более детальный учет), может быть целесообразно вместо автоматического включения возврата в ОтчетОРозничныхПродажах, формировать отдельный документ ВозвратТоваровОтПокупателя. Этот документ позволяет вручную указать номенклатуру, количество и цену возврата, а также привязать его к конкретному документу реализации, если это возможно. Однако для массовых ежедневных операций это может быть неэффективно.
Обратите внимание на то, как 1С учитывает себестоимость при возврате. Если система не может найти документ отгрузки или сопоставить возврат с конкретной продажей, возврат может быть проведен без корректного учета себестоимости, что также может влиять на финансовые результаты и отчетность.
Любые изменения в логике обмена или формировании отчетов должны быть тщательно протестированы. Мы рекомендуем провести тестирование на тестовой базе данных, воспроизведя все возможные сценарии продаж и возвратов (с разными ценами, со скидками, возвраты в день продажи и в другие дни) и убедиться, что Z-отчеты Frontol и ОтчетыОРозничныхПродажах в 1С теперь совпадают.
Имейте в виду, что точные названия модулей, процедур и объектов 1С могут отличаться в зависимости от используемой конфигурации (1С:Розница, 1С:УправлениеТорговлей, 1С:КомплекснаяАвтоматизация, 1С:БухгалтерияПредприятия) и ее версии. При поиске участков для модификации всегда ориентируйтесь на актуальную документацию и структуру вашей информационной базы.
Расхождения между Z-отчетом Frontol и ОтчетомОРозничныхПродажах в 1С при возвратах товаров, особенно со скидками, являются распространенной проблемой, вызванной стремлением 1С к "схлопыванию" позиций и потенциальной потерей информации о первоначальных ценах. Мы выяснили, что наиболее эффективное решение заключается в модификации логики загрузки данных в 1С, чтобы предотвратить исключение строк из отчета, если их суммарные значения (продажа минус возврат) не равны нулю. Реализация этого решения требует глубокого понимания структуры обмена и программирования на платформе 1С, но позволит нам добиться полной корреляции между кассовыми данными и учетной системой, обеспечивая точность финансовой отчетности и управленческого учета.