Как решить проблему проведения приходного и расходного документов в одну секунду в 1С?

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

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

В этой статье мы подробно разберем, почему возникает эта проблема на уровне платформы, как устроен механизм момента времени и уникальных идентификаторов (GUID), а также рассмотрим все возможные стандартные и программные способы обхода этой коллизии.

Почему это происходит? Анализируем платформенные механизмы

Для того чтобы понять суть проблемы, нам необходимо детально рассмотреть, как платформа 1С позиционирует документы на временной шкале. Время в системе хранится с точностью до одной секунды. Если два или более документов записаны в одну и ту же секунду (например, 15.10.2023 14:30:22), то стандартного показателя времени становится недостаточно для однозначного определения последовательности.

В таких случаях платформа использует системное понятие Момент времени. Объект МоментВремени состоит из двух ключевых компонентов:

  1. Дата и время документа (с точностью до секунды).
  2. Ссылка на сам документ (уникальный идентификатор GUID).

Когда СУБД (будь то Microsoft SQL Server, PostgreSQL или файловый вариант базы данных) выстраивает документы на оси времени для расчета остатков, она сортирует их сначала по дате и времени. Если они совпадают, сортировка происходит по значению уникального идентификатора ссылки (GUID). Поскольку GUID генерируется платформой автоматически и не зависит от хронологического порядка ввода документов человеком, возникает фактор случайности. Документ расхода, созданный физически позже, может получить GUID, который при сортировке окажется "меньше" GUID приходного документа. В итоге расходный документ встает перед приходным, и при списании программа выдает ошибку.

Важно отметить, почему стандартное использование объекта Граница при запросе остатков не решает проблему в данном случае. Многие разработчики пытаются получить остатки с использованием конструкции вида Новый Граница(МоментВремени, ВидГраницы.Включая). Однако, если из-за случайного распределения GUID МоментВремени расхода оказался раньше, никакая граница не поможет: запрос физически не "увидит" документ прихода, так как на временной шкале он находится в "будущем" относительно расхода.

Решение 1. Программный сдвиг времени (доработка через расширение)

Рассмотрим первый практический вариант решения проблемы — программный контроль времени при записи документа. Мы можем перехватывать запись расходного документа в событии ПередЗаписью и проверять, существуют ли приходы по этой же номенклатуре в ту же секунду. Если приход обнаружен, мы искусственно увеличиваем время расходного документа на 1 секунду.

Давайте посмотрим на пример реализации такого алгоритма с помощью запроса к регистру накопления:


// Процедура-обработчик события ПередЗаписью расходного документа
Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
    Если РежимЗаписи = РежимЗаписиДокумента.Проведение Тогда
        // Создаем запрос для проверки наличия приходов в эту же секунду
        Запрос = Новый Запрос;
        Запрос.Текст = 
            "ВЫБРАТЬ ПЕРВЫЕ 1
            |	1
            |ИЗ
            |	РегистрНакопления.Запасы КАК Запасы
            |ГДЕ
            |	Запасы.Период = &Период
            |	И Запасы.ВидДвижения = ЗНАЧЕНИЕ(ВидДвиженияНакопления.Приход)
            |	И Запасы.Номенклатура В (&СписокНоменклатуры)";
        
        Запрос.УстановитьПараметр("Период", ЭтотОбъект.Дата);
        Запрос.УстановитьПараметр("СписокНоменклатуры", ЭтотОбъект.Запасы.ВыгрузитьКолонку("Номенклатура"));
        
        РезультатЗапроса = Запрос.Выполнить();
        Если Не РезультатЗапроса.Пустой() Тогда
            // Сдвигаем время расхода на одну секунду вперед
            ЭтотОбъект.Дата = ЭтотОбъект.Дата + 1;
        КонецЕсли;
    КонецЕсли;
КонецПроцедуры

Важное ограничение: проблема конца дня (23:59:59). Если мы попытаемся прибавить одну секунду к времени 23:59:59, документ автоматически перейдет на следующие сутки. В бухгалтерском и управленческом учете это может привести к серьезным искажениям отчетности (особенно если это граница месяца или квартала). Чтобы обойти это ограничение, используют обратный сдвиг: принудительно устанавливают время всех приходов на начало дня (например, на 00:00:00 или 00:00:01), а расходы оставляют на текущем времени или прижимают к концу дня.

Решение 2. Использование типового механизма автоустановки времени

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

Давайте разберем по шагам, как активировать и настроить этот функционал:

  1. Перейдем в раздел Администрирование (или "Настройки"), далее выберем пункт Проведение документов.
  2. Найдем опцию "Время документов устанавливать автоматически" и установим флаг.
  3. После активации этой настройки платформа начнет автоматически распределять время документов различных типов в рамках одного дня, исключая их пересечение в одну секунду.

При включении этого режима документы записываются по следующим правилам:

Этот простой шаг полностью ликвидирует проблему пересечения прихода и расхода в одну секунду на уровне бизнес-логики без необходимости вносить изменения в код конфигурации.

Решение 3. Переход на ордерную схему учета

Рассмотрим ситуацию в крупных торговых или производственных компаниях, где финансовые документы оформляются менеджерами в офисе, а фактическая отгрузка и приемка происходят непосредственно на складе. В таких случаях идеальным решением является разделение финансового и складского контуров с помощью ордерного склада.

При использовании ордерной схемы:

Решение 4. Отложенный расчет себестоимости и партионного учета

Выясним причину, почему система вообще требует строгой последовательности секунд при оперативном проведении. Это связано с расчетом себестоимости списываемых партий в реальном времени. В высоконагруженных системах от этого подхода часто отказываются в пользу производительности.

Современная методология разработки 1С рекомендует разделять контроль остатков на два этапа:

Такой подход полностью снимает с пользователей нагрузку по контролю за секундами и существенно повышает общую отказоустойчивость системы.

← На главную