Как реализовать моментальный расчет сдачи при наборе суммы без потери фокуса в 1С

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

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

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

Почему сбрасывается текст или теряется фокус ввода

Выясним причину, по которой стандартная форма управляемого приложения ведет себя подобным образом при динамическом обновлении:

  1. Автоматическая синхронизация реквизитов: По умолчанию поле ввода связано с реквизитом формы определенного типа (например, Число). При программном изменении любых связанных данных на форме платформа пытается обновить визуальное состояние элемента управления, что приводит к перезаписи текущего буфера редактирования значением реквизита.
  2. Контекстные серверные вызовы: Если в момент набора символа происходит неявный или явный вызов сервера (директива &НаСервере), управляемая форма перерисовывается, что неизбежно приводит к потере фокуса каретки ввода.
  3. Попытка перезаписи значения реквизита на каждом символе: Если прямо в процессе набора текста принудительно перезаписывать сам реквизит, к которому привязано текущее поле, курсор сбрасывается в начало строки или текст выделяется целиком.

Решение 1. Использование события ИзменениеТекстаРедактирования и настройка свойства поля

Проанализируем базовый и наиболее правильный подход на управляемых формах без вызовов сервера и сторонних компонент.

Разберем по шагам порядок настройки элемента:

  1. В конфигураторе открываем свойства поля ввода внесенной суммы.
  2. Находим свойство Обновление текста редактирования и устанавливаем его в значение Не использовать (или При изменении значения, чтобы платформа не пыталась принудительно форматировать незавершенный текст).
  3. Для этого поля ввода создаем обработчик события ИзменениеТекстаРедактирования на клиенте.
  4. Внутри обработчика производим расчет сдачи исключительно на клиенте (директива &НаКлиенте) и выводим результат в отдельный реквизит формы или элемент отображения (например, заголовок декорации или реквизит Сдача).

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


&НаКлиенте
Процедура ВнесеноИзменениеТекстаРедактирования(Элемент, Текст, СтандартнаяОбработка)
    // Преобразуем введенный текст в число
    ВнесеннаяСумма = Число(Текст);
    
    // Рассчитываем сдачу на основе известной суммы чека
    Сдача = ВнесеннаяСумма - СуммаЧека;
КонецПроцедуры

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


&НаКлиенте
Процедура ВнесеноИзменениеТекстаРедактирования(Элемент, Текст, СтандартнаяОбработка)
    ВнесеннаяСумма = Число(Текст);
    ТекущаяСдача = ВнесеннаяСумма - СуммаЧека;
    
    Если ТекущаяСдача >= 0 Тогда
        Элементы.ДекорацияСдача.Заголовок = СтрШаблон("Сдача: %1 руб.", ТекущаяСдача);
    Иначе
        Элементы.ДекорацияСдача.Заголовок = "Недостаточно средств";
    КонецЕсли;
КонецПроцедуры

Важно: Не выполняйте внутри этого обработчика запись в сам реквизит Внесено, пока пользователь не завершит ввод. Платформа запишет финальное значение в реквизит автоматически при потере фокуса или нажатии клавиши подтверждения.

Решение 2. Асинхронная задержка расчета (Debounce)

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

Рассмотрим пример реализации через асинхронную задержку по таймеру:


&НаКлиенте
Перем пСуммаВвода, пТаймер;

&НаКлиенте
Процедура ВнесеноИзменениеТекстаРедактирования(Элемент, Текст, СтандартнаяОбработка)
    пСуммаВвода = Число(Текст);
    ВыполнитьПроверкуСдачи();
КонецПроцедуры

&НаКлиенте
Асинх Процедура ВыполнитьПроверкуСдачи()
    Если пТаймер <> 0 Тогда
        Возврат;
    КонецЕсли;
    
    пТаймер = ТекущаяУниверсальнаяДатаВМиллисекундах();
    п = ТекущаяУниверсальнаяДатаВМиллисекундах();
    
    Пока (п - пТаймер) < 300 Цикл 
        п = ТекущаяУниверсальнаяДатаВМиллисекундах(); 
    КонецЦикла;
    
    пТаймер = 0;
    
    // Отображаем рассчитанный результат
    Сдача = пСуммаВвода - СуммаЧека;
КонецПроцедуры

Альтернативные подходы

В типовых конфигурациях 1С (таких как 1С:Розница и 1С:Управление торговлей) для исключения ошибок ручного ввода часто используются другие эргономичные решения:

  1. Быстрые кнопки купюр: В интерфейс кассира добавляются кнопки с популярными номиналами наличных (+100, +500, +1000, +5000, а также Без сдачи). Нажатие на кнопку сразу формирует сумму без использования клавиатуры и моментально рассчитывает сдачу.
  2. Поле HTML-документа: Если требуется сложная интерактивная маска ввода с нестандартной визуализацией, область ввода реализуется на базе HTML/JS внутри элемента ПолеHTMLДокумента, передавая финальные данные в 1С через события клиентского скрипта.
← На главную