Как решить проблему блокировок и потери чеков ККТ при обмене в РИБ на УТ 10.3?

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

При работе в распределенной информационной базе (РИБ) на базе конфигурации «1С:Управление торговлей 10.3» часто возникает критическая ситуация: во время ежечасного обмена данными или при одновременной работе нескольких кассиров блокируются таблицы базы данных. В результате чек на фискальном регистраторе (ККТ) физически пробивается, но в самой программе 1С документ ЧекККМ не записывается или не проводится из-за ошибки ожидания блокировки. Кассирам приходится вручную сверять данные с личным кабинетом ОФД, что замедляет работу и приводит к кассовым разрывам.

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

В чем причина блокировок и «потерянных» чеков?

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


НовыйЧек = Документы.ЧекККМ.СоздатьДокумент();
// Заполнение реквизитов чека...
НомерЧекаККТ = ПробитьЧекНаККМ(); // Физическая отправка команды на ККТ
НовыйЧек.НомерЧека = НомерЧекаККТ;
НовыйЧек.Записать(РежимЗаписиДокумента.Проведение);

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

Кроме того, в конфигурации «Управление торговлей 10.3» по умолчанию используется автоматический режим блокировок. Это означает, что при проведении документа СУБД блокирует таблицы целиком, а не отдельные строки, что парализует работу всех кассиров при любой интенсивной операции.

---

Решение 1. Изменение алгоритма: «Сначала запись черновика, потом печать»

Рассмотрим правильный и безопасный алгоритм взаимодействия с фискальным накопителем. Наша главная задача — сделать так, чтобы документ сначала появился в базе 1С в виде уникальной записи (черновика), и только после этого отправлялась команда на печать.

Разберем этот процесс по шагам:

  1. Запись документа без проведения. Мы записываем объект в режиме Запись. Эта операция выполняется мгновенно и практически не вызывает блокировок. Документ получает постоянную ссылку в базе данных.
  2. Отправка команды на ККТ. Мы передаем данные на фискальный регистратор. Если на этом этапе происходит сбой (например, закончилась чековая лента или пропала связь с кассой), документ остается в базе со статусом «Не проведен», и мы можем повторить попытку позже без потери данных.
  3. Проведение документа. Только после успешного ответа ККТ мы записываем фискальные признаки (номер чека, номер смены, ФПД) в документ и проводим его.

Посмотрим на пример реализации данного алгоритма в коде:


// Шаг 1: Записываем чек как черновик
Попытка
    СсылкаНаДокумент = ПолучитьСсылкуНовогоДокумента();
    НовыйЧек.Записать(РежимЗаписиДокумента.Запись);
Исключение
    ВызватьИсключение "Не удалось предварительно записать чек в базу: " + ОписаниеОшибки();
КонецПопытки;

// Шаг 2: Пробиваем на ККТ
ПараметрыЧека = СформироватьПакетДляККТ(НовыйЧек);
РезультатПечати = ПробитьЧекНаФизическомУстройстве(ПараметрыЧека);

Если РезультатПечати.Успех Тогда
    // Шаг 3: Записываем фискальный номер и проводим документ
    НовыйЧек.НомерЧекаККМ = РезультатПечати.НомерЧека;
    НовыйЧек.Пробит = Истина;
    Попытка
        НовыйЧек.Записать(РежимЗаписиДокумента.Проведение);
    Исключение
        // Если проведение заблокировано, чек УЖЕ записан! Данные не потеряны.
        ЗаписатьВЛогОшибок("Чек № " + РезультатПечати.НомерЧека + " пробит на ККТ, но не проведен в 1С. Требуется ручное допроведение.");
    КонецПопытки;
Иначе
    ВызватьИсключение "Ошибка печати чека на ККТ: " + РезультатПечати.Ошибка;
КонецЕсли;

---

Решение 2. Исключение физической печати из транзакции 1С

Часто разработчики совершают ошибку, оборачивая весь процесс продажи в явную транзакцию с помощью операторов НачатьТранзакцию() и ЗафиксироватьТранзакцию(). Физическая печать чека на ККТ может занимать от 2 до 5 секунд. Если этот процесс находится внутри транзакции 1С, все таблицы СУБД, задействованные в проведении, будут заблокированы на эти секунды для всех остальных пользователей!

Правило: Никогда не вызывайте методы работы с торговым оборудованием (драйвер ККТ) внутри транзакционных блоков 1С. Процедура фискализации должна выполняться строго вне транзакции.

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

---

Решение 3. Настройка СУБД и включение механизма RCSI

Если ваша база данных работает на MS SQL Server, частой причиной блокировок кассиров во время обмена РИБ является чтение данных процессом обмена. Чтение накладывает разделяемые блокировки (Shared Locks), которые конфликтуют с монопольными блокировками (Exclusive Locks) при записи чеков.

Чтобы решить эту проблему без изменения кода, включите режим версионирования строк на уровне SQL Server (Read Committed Snapshot Isolation — RCSI). Выполните следующий запрос в SQL Server Management Studio для вашей базы данных:


ALTER DATABASE [Имя_Вашей_Базы_Данных] 
SET SINGLE_USER WITH ROLLBACK IMMEDIATE;

ALTER DATABASE [Имя_Вашей_Базы_Данных] 
SET READ_COMMITTED_SNAPSHOT ON;

ALTER DATABASE [Имя_Вашей_Базы_Данных] 
SET MULTI_USER;

После включения RCSI процессы чтения (например, выгрузка данных в РИБ или построение отчетов администратором) будут читать «снимки» данных из базы tempdb, вообще не блокируя транзакции записи, совершаемые кассирами на фронт-офисе.

---

Решение 4. Оптимизация планов обмена РИБ

Проанализируем структуру распределенной информационной базы. Зачем передавать каждый индивидуальный ЧекККМ через каналы обмена РИБ в центральный офис каждый час? Это порождает колоссальную нагрузку на каналы связи и СУБД.

По классической методологии розничной торговли 1С:

Рекомендуется исключить документ ЧекККМ из состава отправляемых объектов в планах обмена РИБ. Настройте правила так, чтобы в центральную базу передавался только итоговый Отчет о розничных продажах один раз в день (после закрытия смены). Это снизит транзакционную нагрузку во время ежечасных обменов практически до нуля.

---

Решение 5. Увеличение времени ожидания блокировки

Если параллельная работа кассиров неизбежна (например, две кассы работают в одной локальной базе на сервере), а блокировки все же кратковременно возникают, можно увеличить время ожидания блокировки. Вместо вывода моментального сообщения об ошибке система просто заставит сеанс второго кассира подождать 5-10 секунд, пока завершится проведение первого чека.

Установите этот параметр при старте системы или в настройках параметров базы данных:


// Установка времени ожидания блокировки в секундах
УстановитьВремяОжиданияБлокировкиДанных(15);

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

← На главную