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