Мы сталкиваемся с распространенной ситуацией, когда по различным причинам, таким как отключение электроэнергии, кассовая смена не была закрыта вовремя, и Z-отчет был сформирован на следующий день. В результате этого 1С:Управление торговлей 10.3 (УТ 10.3) не сформировала необходимый "Отчет о розничных продажах" за предыдущий день. Возникает вопрос: как нам сформировать этот отчет, чтобы корректно отразить выручку и движения товаров?
Для начала, давайте разберем, как обычно работает механизм формирования "Отчета о розничных продажах" в 1С:УТ 10.3. Документ "Отчет о розничных продажах" является центральным для учета розничной выручки и формируется, как правило, автоматически при закрытии кассовой смены. В этот момент система обрабатывает все "Чеки ККМ", зарегистрированные в течение смены, агрегирует их данные и создает единый документ "Отчет о розничных продажах". После успешного создания отчета, "Чеки ККМ" могут получать статус "Архивный" или "Свернут" и их движения "переносятся" в сформированный отчет. При этом данные о продажах регистрируются в регистре накопления "Товары в рознице", и именно по этому регистру мы можем определить, были ли чеки уже свернуты или все еще "висят" несвернутыми.
Наша задача заключается в том, чтобы найти несвернутые "Чеки ККМ" за нужную дату и на их основании сформировать "Отчет о розничных продажах". Рассмотрим несколько подходов к решению этой проблемы.
Одним из предложенных на форуме вариантов является попытка повторного запуска процедуры закрытия кассовой смены. Хотя интуитивно кажется, что если Z-отчет уже снят, то смена закрыта и повторное закрытие невозможно, в контексте 1С это может иметь свои нюансы. Физический Z-отчет на кассовом аппарате действительно снимается один раз, но внутренняя обработка "Чеков ККМ" в 1С может быть отдельным процессом.
Сервис / Торговое оборудование / Работа с ККМ / Закрытие кассовой смены.Товары в рознице. Если чеки были успешно свернуты, движения по регистру должны быть соответствующим образом учтены в новом отчете.Важно понимать, почему этот метод может сработать, несмотря на снятый Z-отчет. Часто закрытие кассовой смены в 1С состоит из двух частей: команды фискальному регистратору на снятие Z-отчета и внутренней обработки данных по "Чекам ККМ". Если первая часть (снятие Z-отчета) произошла, а вторая (формирование отчета в 1С) не завершилась по какой-либо причине (например, обрыв связи или ошибка), то "Чеки ККМ" могут остаться "несвернутыми". Повторный запуск закрытия с правильной датой дает шанс системе завершить именно вторую часть процесса.
Если стандартный подход с повторным закрытием смены не сработал, или если мы хотим иметь более точечный контроль над процессом, самым надежным решением будет создание собственной внешней обработки. Этот подход является более трудоемким, но предоставляет максимальную гибкость и контроль.
ЗакрытиеКассовойСмены или в каком-либо общем модуле, который вызывается при его проведении. Мы выясним, какие регистры затрагиваются (прежде всего ТоварыВРознице, а также ВыручкаККМ, Продажи), и как происходит выборка "несвернутых" чеков.КассаККМ, чтобы указать, по какой кассе необходимо сформировать отчет.ДатаОтчета, для указания даты, за которую формируется "Отчет о розничных продажах".ОтчетОРозничныхПродажах у документа ЧекККМ и наличие движений по регистру ТоварыВРознице.Рассмотрим пример запроса для получения несвернутых чеков:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ЧекККМ.Ссылка КАК Ссылка,
| ЧекККМ.Номер КАК Номер,
| ЧекККМ.Дата КАК Дата,
| ЧекККМ.КассаККМ КАК КассаККМ,
| ЧекККМ.Склад КАК Склад,
| ЧекККМ.Организация КАК Организация,
| ЧекККМ.СуммаДокумента КАК СуммаДокумента,
| ЧекККМ.ВидОплаты КАК ВидОплаты,
| ЧекККМ.ВалютаДокумента КАК ВалютаДокумента
|ИЗ
| Документ.ЧекККМ КАК ЧекККМ
|ГДЕ
| ЧекККМ.Дата МЕЖДУ &НачалоДня И &КонецДня
| И ЧекККМ.КассаККМ = &КассаККМ
| И ЧекККМ.ОтчетОРозничныхПродажах ЕСТЬ NULL
| И ЧекККМ.Проведен";
Запрос.УстановитьПараметр("НачалоДня", НачалоДня(ДатаОтчета));
Запрос.УстановитьПараметр("КонецДня", КонецДня(ДатаОтчета));
Запрос.УстановитьПараметр("КассаККМ", КассаККМ);
РезультатЗапроса = Запрос.Выполнить().Выгрузить();
ОтчетОРозничныхПродажах и заполним его данными. Нам потребуется агрегировать информацию из всех найденных чеков: суммы, товары, виды оплат и т.д.Примерный код для создания и заполнения отчета:
Если РезультатЗапроса.Количество() > 0 Тогда
НовыйОтчет = Документы.ОтчетОРозничныхПродажах.СоздатьДокумент();
НовыйОтчет.Дата = ДатаОтчета;
НовыйОтчет.КассаККМ = КассаККМ;
НовыйОтчет.Организация = РезультатЗапроса[0].Организация; // Возьмем из первого чека
НовыйОтчет.Склад = РезультатЗапроса[0].Склад; // Возьмем из первого чека
НовыйОтчет.ВалютаДокумента = РезультатЗапроса[0].ВалютаДокумента;
Для Каждого СтрокаЧека Из РезультатЗапроса Цикл
ЧекОбъект = СтрокаЧека.Ссылка.ПолучитьОбъект();
Если ЧекОбъект.Проведен Тогда
// Добавляем товары в табличную часть "Товары" отчета
Для Каждого СтрокаТовара Из ЧекОбъект.Товары Цикл
СтрокаТабЧастиТовары = НовыйОтчет.Товары.Добавить();
СтрокаТабЧастиТовары.Номенклатура = СтрокаТовара.Номенклатура;
СтрокаТабЧастиТовары.ХарактеристикаНоменклатуры = СтрокаТовара.ХарактеристикаНоменклатуры;
СтрокаТабЧастиТовары.Количество = СтрокаТовара.Количество;
СтрокаТабЧастиТовары.Цена = СтрокаТовара.Цена;
СтрокаТабЧастиТовары.Сумма = СтрокаТовара.Сумма;
СтрокаТабЧастиТовары.ЕдиницаИзмерения = СтрокаТовара.ЕдиницаИзмерения;
СтрокаТабЧастиТовары.СтавкаНДС = СтрокаТовара.СтавкаНДС;
СтрокаТабЧастиТовары.СуммаНДС = СтрокаТовара.СуммаНДС;
СтрокаТабЧастиТовары.СкидкаНаценка = СтрокаТовара.СкидкаНаценка;
СтрокаТабЧастиТовары.ПроцентСкидкиНаценки = СтрокаТовара.ПроцентСкидкиНаценки;
СтрокаТабЧастиТовары.СерияНоменклатуры = СтрокаТовара.СерияНоменклатуры;
КонецЦикла;
// Добавляем оплаты в табличную часть "Оплата" отчета
Для Каждого СтрокаОплаты Из ЧекОбъект.Оплата Цикл
СтрокаТабЧастиОплата = НовыйОтчет.Оплата.Добавить();
СтрокаТабЧастиОплата.ВидОплаты = СтрокаОплаты.ВидОплаты;
СтрокаТабЧастиОплата.Сумма = СтрокаОплаты.Сумма;
СтрокаТабЧастиОплата.СчетОрганизации = СтрокаОплаты.СчетОрганизации;
КонецЦикла;
КонецЕсли;
КонецЦикла;
Попытка
НовыйОтчет.Записать(РежимЗаписиДокумента.Проведение);
Сообщить("Отчет о розничных продажах №" + НовыйОтчет.Номер + " от " + НовыйОтчет.Дата + " успешно сформирован и проведен.");
Исключение
Сообщить("Ошибка при проведении Отчета о розничных продажах: " + ОписаниеОшибки());
Возврат;
КонецПопытки;
// После успешного проведения, обновляем ссылку в Чеках ККМ
Для Каждого СтрокаЧека Из РезультатЗапроса Цикл
ЧекОбъект = СтрокаЧека.Ссылка.ПолучитьОбъект();
Если ЧекОбъект.Проведен Тогда
ЧекОбъект.ОтчетОРозничныхПродажах = НовыйОтчет.Ссылка;
Попытка
ЧекОбъект.Записать();
Исключение
Сообщить("Ошибка при обновлении Чека ККМ №" + ЧекОбъект.Номер + ": " + ОписаниеОшибки());
КонецПопытки;
КонецЕсли;
КонецЦикла;
Иначе
Сообщить("Не найдено несвернутых Чеков ККМ за указанную дату и кассу.");
КонецЕсли;
ОтчетОРозничныхПродажах необходимо программно провести. Это вызовет движения по регистрам (ТоварыВРознице, Продажи, ДенежныеСредства и др.), которые приведут данные в соответствие.ОтчетОРозничныхПродажах ссылку на вновь созданный отчет. Это позволит системе корректно определить, какие чеки уже были учтены.Данный подход требует знаний программирования в 1С, но позволяет решить проблему даже в самых сложных случаях, когда стандартные механизмы не срабатывают.
Независимо от выбранного подхода, всегда проводите тщательную проверку результатов:
Товары в рознице до и после выполнения наших действий. Мы должны убедиться, что "Чеки ККМ", которые ранее имели движения, теперь корректно "закрыты" документом "Отчет о розничных продажах".Журнал регистрации в 1С на предмет любых ошибок, связанных с проведением документов или инициализацией модулей. Это поможет нам выявить скрытые проблемы.Выбирая любой из этих методов, мы сможем восстановить целостность данных в нашей 1С:УТ 10.3 и корректно учесть розничные продажи, даже если кассовая смена была закрыта с задержкой.