Как реализовать оприходование партий по методу LIFO для выравнивания остатков в 1С

Программист 1С:Управление торговлей Управленческий учет Торговля и дистрибуция
← На главную

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

Разберем ситуацию, когда нам необходимо «дозаполнить» партийный учет, ориентируясь на последние реальные поступления товара. Мы будем использовать логику LIFO (Last In, First Out) — то есть будем искать самые свежие документы прихода, чтобы по ним восстановить недостающее количество в партиях. Рассмотрим подробно, как это реализовать программно.

Анализ исходной проблемы

Представим сценарий: на складе числится 10 единиц товара «Клеящий карандаш», а по регистру партий — всего 4 единицы. Нам нужно оприходовать недостающие 6 единиц. Чтобы себестоимость остатков была максимально приближена к актуальной, логично взять данные из последних приходных накладных. Если последняя накладная была на 2 штуки, а предпоследняя — на 10, то мы должны взять 2 штуки из последней и еще 4 из предпоследней.

Шаг 1: Подготовка запроса для получения последних приходов

Для решения задачи нам не подходят остатки, так как по партиям у нас может быть пусто или данные некорректны. Нам нужны именно обороты прихода. Проанализируем структуру запроса. Нам важно получить список документов оприходования, отсортированных по дате в обратном порядке.

Рассмотрим пример запроса, который собирает данные о поступлениях:


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

Запрос.УстановитьПараметр("Номенклатура", ВыбраннаяНоменклатура);
// Период лучше брать достаточно большой, чтобы найти старые поступления, если свежих мало
Запрос.УстановитьПараметр("НачалоПериода", ДобавитьМесяц(ТекущаяДата(), -12)); 
Запрос.УстановитьПараметр("КонецПериода", ТекущаяДата());

Важный нюанс: В запросе мы обязательно используем УПОРЯДОЧИТЬ ПО Период УБЫВ. Это и есть техническая реализация принципа LIFO в контексте выборки: самые новые документы окажутся в начале списка.

Шаг 2: Алгоритм распределения количества по выборке

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

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


РезультатЗапроса = Запрос.Выполнить();
Выборка = РезультатЗапроса.Выбрать();

НужноОприходовать = 10; // Например, нам не хватает 10 штук
ТаблицаРезультат = Новый ТаблицаЗначений;
ТаблицаРезультат.Колонки.Добавить("Партия");
ТаблицаРезультат.Колонки.Добавить("Количество");

Пока Выборка.Следующий() И НужноОприходовать > 0 Цикл
    
    // Вычисляем, сколько мы можем взять из текущей партии
    КоличествоИзПартии = Мин(Выборка.Количество, НужноОприходовать);
    
    // Добавляем строку в результат
    НоваяСтрока = ТаблицаРезультат.Добавить();
    НоваяСтрока.Партия = Выборка.Партия;
    НоваяСтрока.Количество = КоличествоИзПартии;
    
    // Уменьшаем счетчик остатка
    НужноОприходовать = НужноОприходовать - КоличествоИзПартии;
    
КонецЦикла;

// Если после цикла НужноОприходовать > 0, значит истории приходов не хватило
Если НужноОприходовать > 0 Тогда
    // Здесь можно либо выдать предупреждение, либо создать пустую партию
    // (например, текущий документ оприходования)
    Сообщить("Внимание: истории поступлений не хватило на " + НужноОприходовать + " шт.");
КонецЕсли;

Шаг 3: Особенности работы с сериями и стоимостью

При реализации данного алгоритма в реальной базе 1С:УТ 10.3, следует обратить внимание на следующие моменты:

  1. Разрезы учета: Обязательно делайте отбор не только по Номенклатура, но и по ХарактеристикаНоменклатуры и СерияНоменклатуры. Если вы оприходуете товар на партию, где была другая серия, вы создадите еще больший беспорядок в регистрах.
  2. Расчет стоимости: В регистр партий нужно записывать не только количество, но и стоимость. Если ваша цель — просто выровнять регистры без изменения финансового результата, можно брать среднюю стоимость из документов прихода или текущую среднюю по складу.
  3. Выбор регистра: Если вы обнаружили расхождение, при котором на складе товар есть, а в партиях нет, использование документа «Оприходование товаров» увеличит остаток на складе. В этом случае правильнее использовать документ КорректировкаЗаписейРегистров, чтобы сделать движения только по регистру ПартииТоваровНаСкладах.

Альтернативный подход: Использование нарастающего итога в запросе

Если записей о приходах очень много, перебор выборки в цикле может быть не самым быстрым решением. Можно переложить часть логики на СУБД, вычислив нарастающий итог прямо в запросе. Рассмотрим, как это выглядит концептуально:

Мы соединяем таблицу приходов саму с собой по условию «Дата прихода из таблицы А <= Даты прихода из таблицы Б». Это позволяет для каждой строки получить сумму всех предыдущих (или последующих, если сортируем по убыванию) поступлений. Таким образом, мы можем сразу в запросе отсечь те строки, где накопленная сумма уже превысила наш лимит в 10 штук.

Однако для разовых задач по выравниванию остатков вариант с простым циклом (как в Шаге 2) является более читаемым, простым в отладке и вполне производительным.

Заключение

Метод LIFO при оприходовании — это эффективный инструмент «реанимации» партийного учета. Помните, что перед выполнением таких корректировок крайне рекомендуется запустить стандартную обработку «Проведение по партиям». Возможно, система сама распределит остатки, если документы просто были проведены в неправильном порядке. Если же это не помогло, описанный выше программный метод позволит вам восстановить учет, опираясь на актуальные цены последних поставок.

← На главную