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