При работе в программе 1С:Розница (редакция 2.2 и выше) часто возникает необходимость настроить раздельную нумерацию для различных касс. Это логично: бухгалтерии и владельцам бизнеса удобнее видеть четкую последовательность документов ПКО (Приходный кассовый ордер) и РКО (Расходный кассовый ордер) по каждой конкретной точке или кассе. Однако программисты часто сталкиваются с ситуацией, когда на локальном компьютере (в файловой базе) всё работает идеально, а после выгрузки в рабочую среду на SQL-сервер нумерация начинает вести себя непредсказуемо. Рассмотрим подробнее, почему это происходит и как решить проблему программными методами.
Представим типичную ситуацию: у нас есть две кассы. Для Кассы-1 мы задали префикс "К1", для Кассы-2 — "К2". Мы ожидаем, что документы будут нумероваться так:
В файловом режиме (на ноутбуке разработчика) система отрабатывает корректно. Но у клиента в клиент-серверном варианте (SQL) происходит странное: если последний созданный документ по Кассе-2 имел номер 77, то новый документ по Кассе-1 внезапно получает номер К1-000078, игнорируя собственную последовательность. Проанализируем причины такого поведения.
Главное отличие работы 1С на SQL-сервере заключается в оптимизации производительности. Чтобы не обращаться к базе данных за каждым новым номером, кластер серверов 1С "забирает" себе диапазон номеров (обычно по 10 штук за раз). В файловой базе номер определяется в момент записи или вызова метода УстановитьНовыйНомер() непосредственно из таблицы, а в SQL-варианте сервер выдает номер из своего внутреннего кэша.
Если логика разделения по префиксам не была инициализирована должным образом в момент вызова генерации номера, сервер может выдать следующий свободный номер, основываясь на глобальном максимуме всех документов данного типа, просто "приклеив" к нему нужный префикс. Именно поэтому Касса-1 "подхватывает" нумерацию Кассы-2.
В конфигурации 1С:Розница итоговый префикс документа ПКО/РКО собирается динамически. Он может включать в себя:
Если префикс кассы устанавливается в коде уже после того, как сработал стандартный механизм генерации номера, система берет следующий свободный номер в рамках общего "пула". Чтобы нумерация была раздельной, префикс должен быть сформирован до или строго в момент вызова события ПриУстановкеНовогоНомера.
Как показывает практика, даже если код формирования префиксов верен, кэш сервера приложений может "застрять" на старых значениях. В этом случае не помогают ни очистка кэша пользователя, ни тестирование и исправление базы данных (ТиИ). Выясним, какое средство является наиболее эффективным.
Существует специальный системный метод ОбновитьНумерациюОбъектов(). Этот метод принудительно заставляет сервер приложений очистить кэш номеров для конкретного типа объекта и заново проанализировать физическую таблицу в базе данных SQL, чтобы найти реальный максимальный номер для каждого префикса.
Разберем по шагам, как выполнить это действие. Поскольку это программный метод, нам потребуется создать небольшую внешнюю обработку или воспользоваться консолью кода. Рассмотрим пример кода для документов ПКО и РКО:
// Пример кода для обновления нумерации кассовых документов
ОбновитьНумерациюОбъектов(Метаданные.Документы.ПриходныйКассовыйОрдер);
ОбновитьНумерациюОбъектов(Метаданные.Документы.РасходныйКассовыйОрдер);
Сообщить("Нумерация кассовых документов успешно обновлена в кэше сервера!");
Этот код необходимо выполнить непосредственно в той базе, где наблюдаются проблемы с номерами. После его выполнения сервер сбросит накопленные диапазоны и при следующем создании документа обратится к таблице SQL, чтобы вычислить номер корректно, исходя из установленного префикса.
Если использование метода ОбновитьНумерациюОбъектов помогает лишь временно, необходимо проверить, как именно назначается номер. В современных редакциях 1С:Розница (2.2, 2.3, 3.0) логика часто скрыта не в модулях самих документов, а в подписках на события. Проанализируем ситуацию:
Общие -> Подписки на события.ПриУстановкеНовогоНомераДокумента или УстановитьПрефиксИнформационнойБазыИОрганизацииНомеруДокумента.Важно помнить, что в процедуре подписки код должен определять кассу документа и добавлять её префикс к стандартному префиксу организации. Если префикс кассы не успевает записаться в реквизиты объекта до того, как система попытается вычислить номер, возникнет ошибка нумерации. Посмотрим на пример правильной структуры процедуры:
Процедура ПриУстановкеНовогоНомераДокумента(Источник, СтандартнаяОбработка, Префикс) Экспорт
// Если это кассовый документ, добавим префикс кассы
Если ТипЗнч(Источник) = Тип("ДокументОбъект.ПриходныйКассовыйОрдер") Тогда
Если ЗначениеЗаполнено(Источник.Касса) И ЗначениеЗаполнено(Источник.Касса.Префикс) Тогда
Префикс = Префикс + Источник.Касса.Префикс;
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Работая с SQL-сервером, важно понимать, почему возникают пропуски в номерах. Когда пользователь нажимает кнопку "Создать", сервер резервирует номер из кэша. Если пользователь передумал, не заполнил документ и просто закрыл форму без записи, зарезервированный номер "пропадает". Он не возвращается в пул. Следующий созданный документ получит следующий по порядку номер. Это нормальное поведение для клиент-серверной архитектуры, направленное на обеспечение высокой скорости работы при одновременной записи документов множеством пользователей.
Чтобы минимизировать проблемы с нумерацией в будущем, рекомендуем придерживаться следующих правил:
Номер в метаданных документа (обычно это 11 символов). Если префикс слишком длинный, "хвост" номера будет обрезан, что приведет к конфликтам дублирования.Строка. Только строковый тип позволяет корректно работать с префиксами.ОбновитьНумерациюОбъектов для основных типов документов, чтобы исключить накопление ошибок в кэше.Подводя итог, можно сказать, что в большинстве случаев проблема "странной" нумерации в 1С:Розница на SQL решается одной строкой кода. Использование ОбновитьНумерациюОбъектов — это эффективный и безопасный способ привести состояние счетчиков номеров в соответствие с фактическими данными в базе.