Как организовать хранение кастомных статусов товаров в строках заказа покупателя в 1С:Управление торговлей 10.3?

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

В типовой конфигурации 1С:Управление торговлей редакции 10.3 статус заказа фиксируется в целом по документу (например, через состояние оплаты, отгрузки или реквизиты статуса). Однако в реальной торговой практике, особенно при синхронизации с интернет-магазинами и маркетплейсами, часто требуется контролировать жизненный цикл каждой отдельной позиции заказа: Принят, Заказан у поставщика, Поступил на склад, Готов к отгрузке, Отгружен. Разберем основные подходы к проектированию этой подсистемы, проанализируем плюсы и минусы различных архитектурных решений, а также решим проблему уникальной адресации строк табличной части.

Вариант 1. Хранение статусов в независимом регистре сведений

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

Проанализируем базовую структуру такого регистра сведений:

  1. Измерение Заказ (тип ДокументСсылка.ЗаказПокупателя).
  2. Измерение ИдентификаторСтроки или КлючСтроки (число или строка с уникальным идентификатором).
  3. Ресурс СтатусТовара (ссылка на перечисление или пользовательский справочник статусов).
  4. Реквизиты ДатаУстановки (тип Дата) и Автор (тип СправочникСсылка.Пользователи) для фиксации аудита изменений.

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

Решение проблемы уникальной идентификации строк документа

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

  1. Штатный метод ПолучитьИдентификатор() строки возвращает временный номер объекта в оперативной памяти текущего сеанса. Он не сохраняется в базе данных и сбрасывается при закрытии формы или перечитывании объекта.
  2. Стандартный реквизит НомерСтроки не является постоянным: при удалении промежуточных позиций, ручной сортировке или программном сдвиге строк номера пересчитываются, что приведет к рассинхронизации связей с регистром сведений.

Для надежной привязки добавим в табличную часть Товары документа ЗаказПокупателя дополнительный реквизит КлючСтроки (тип Число, длина 10, точность 0) либо строковый реквизит для GUID. Разберем пример формирования инкрементного ключа при добавлении новой строки в табличную часть:


Процедура ТоварыПриОкончанииВводаТекста(Элемент, Текст, Значение, СтандартнаяОбработка)
    // Обработка ручного ввода
КонецПроцедуры

Процедура ТоварыПередНачаломДобавления(Элемент, Отказ, Копирование)
    // При программном или интерактивном добавлении
КонецПроцедуры

Процедура ПриЗаписи(Отказ)
    // Гарантируем уникальность ключей строк перед записью документа
    МаксимальныйКлюч = 0;
    Для Каждого Стр Из Товары Цикл
        Если Стр.КлючСтроки > МаксимальныйКлюч Тогда
            МаксимальныйКлюч = Стр.КлючСтроки;
        КонецЕсли;
    КонецЦикла;
    
    Для Каждого Стр Из Товары Цикл
        Если Не ЗначениеЗаполнено(Стр.КлючСтроки) Тогда
            МаксимальныйКлюч = МаксимальныйКлюч + 1;
            Стр.КлючСтроки = МаксимальныйКлюч;
        КонецЕсли;
    КонецЦикла;
КонецПроцедуры

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

Вариант 2. Динамический расчет статуса на основании движений учетных регистров

Рассмотрим альтернативную концепцию: статус не хранится как самостоятельное значение, а рассчитывается динамически по актуальным остаткам типовых регистров накопления УТ 10.3. Этот способ исключает рассинхронизацию данных и ручные ошибки операторов.

Проанализируем логику сопоставления учетных данных и статусов позиций заказа:

  1. Статус «Принят»: заказ проведен, но по позиции еще нет движений по размещению и обеспечению.
  2. Статус «Заказан у поставщика»: по позиции есть остаток в регистре накопления РазмещениеЗаказовПокупателей.
  3. Статус «Готов к отгрузке»: товар зарезервирован на складе под данный заказ (проверяется по остаткам регистра накопления ТоварыВРезервеНаСкладах).
  4. Статус «Отгружен»: остаток долга по регистру ЗаказыПокупателей равен нулю, товар списан документом РеализацияТоваровУслуг.

Динамический расчет обеспечивает 100% точность, однако при большом количестве заказов постоянное вычисление остатков запросами может создавать нагрузку на сервер СУБД. Оптимальный компромисс — выполнять расчет регламентным заданием и складывать готовый срез статусов в плоский регистр сведений исключительно для передачи на веб-витрину сайта.

Оптимизация отображения статусов в форме заказа (обычные формы)

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

Используем специализированное событие табличного поля ПриПолученииДанных. В этот обработчик передается коллекция ОформленияСтрок, содержащая только те строки, которые физически видны на экране монитора в текущий момент.

Разберем пример пакетного считывания данных:


Процедура ТоварыПриПолученииДанных(Элемент, ОформленияСтрок)
    
    МассивКлючей = Новый Массив;
    Для Каждого Оформление Из ОформленияСтрок Цикл
        МассивКлючей.Добавить(Оформление.ДанныеСтроки.КлючСтроки);
    КонецЦикла;
    
    Если МассивКлючей.Количество() = 0 Тогда
        Возврат;
    КонецЕсли;
    
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |   РС.КлючСтроки КАК КлючСтроки,
        |   РС.СтатусТовара КАК СтатусТовара
        |ИЗ
        |   РегистрСведений.СтатусыТоваровВЗаказах КАК РС
        |ГДЕ
        |   РС.Заказ = &Заказ
        |   И РС.КлючСтроки В (&МассивКлючей)";
        
    Запрос.УстановитьПараметр("Заказ", Ссылка);
    Запрос.УстановитьПараметр("МассивКлючей", МассивКлючей);
    
    Выборка = Запрос.Выполнить().Выбрать();
    СоответствиеСтатусов = Новый Соответствие;
    Пока Выборка.Следующий() Цикл
        СоответствиеСтатусов.Вставить(Выборка.КлючСтроки, Выборка.СтатусТовара);
    КонецЦикла;
    
    Для Каждого Оформление Из ОформленияСтрок Цикл
        ТекущийСтатус = СоответствиеСтатусов[Оформление.ДанныеСтроки.КлючСтроки];
        Если ТекущийСтатус <> Неопределено Тогда
            Оформление.Ячейки.КолонкаСтатус.Значение = ТекущийСтатус;
            Оформление.Ячейки.КолонкаСтатус.Текст = Строка(ТекущийСтатус);
        КонецЕсли;
    КонецЦикла;
    
КонецПроцедуры

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

← На главную