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