Почему стандартные обработки 1С имеют ограничение в 65535 видов документов, используют английскую нотацию и как получить движения документа?

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

Давайте вместе разберемся в нескольких интересных и порой неочевидных аспектах платформы 1С:Предприятие, которые часто вызывают вопросы у разработчиков. Мы рассмотрим, почему в некоторых стандартных обработках встречаются загадочные ограничения, почему код написан на английском языке и как правильно работать с движениями документов, чтобы избежать пустых данных.

Ограничение на количество видов документов в 65535: действительно ли оно существует?

В начале обсуждения мы столкнулись с интересным фрагментом кода из стандартной обработки "Проведение документов":


if SelectedDocumentsList.Count > 65535 Then
    ShowMessageBox(, NStr("ru='Не поддерживается более 65535 видов документов.';sys='Processing.TooManyDocumentsKind'", "ru"));
    Return;
EndIf;

Это наблюдение вызвало закономерный вопрос: неужели платформа 1С:Предприятие действительно предполагает наличие более 65535 видов документов в одной конфигурации, и если да, то почему существует такое ограничение? На первый взгляд, число 65535 (которое является 216 - 1) — это классическое максимальное значение для 16-битного целого числа, что очень часто встречается в различных информационных системах как предел для индексации или внутреннего представления данных.

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

Мы также можем вспомнить другие ограничения, связанные с количеством записей, но они, как правило, касаются табличных частей документов, а не видов метаданных:

  1. В платформе 1С:Предприятие 8.3.х максимальное количество строк в табличной части документа составляет 99999. Это ограничение часто называют "искусственным", поскольку оно введено для обеспечения оптимальной производительности типовых решений и применяется в момент записи документа в базу данных.
  2. В будущих релизах платформы (например, в версии 8.3.27) планируется значительное увеличение этого лимита до 999 999 999 записей в табличных частях. Это позволит создавать решения для очень крупных организаций с более детализированными операциями.

Таким образом, ограничение в 65535 видов документов, вероятно, является специфической особенностью реализации определенной служебной логики, а не общим правилом для всей платформы.

Английская нотация в коде 1С:Предприятия: почему так и в каких случаях?

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


if SelectedDocumentsList.Count > 65535 Then
    ShowMessageBox(, NStr("ru='Не поддерживается более 65535 видов документов.';sys='Processing.TooManyDocumentsKind'", "ru"));
    Return;
EndIf;

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

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

Как отмечалось в сообщениях форума, Библиотека стандартных подсистем (БСП) версии 3.0.1.418 и выше является отличным примером такого подхода. БСП — это не самостоятельный конечный продукт, а мощный инструментарий для разработчика, предназначенный для создания новых конфигураций. Он используется для разработки решений, в том числе для иностранных рынков. Поэтому неудивительно, что код БСП и многих стандартных (системных) обработок унифицирован под английскую нотацию. Весь код самой платформы 1С:Предприятие 8, написанной на C++, JavaScript и Java, также использует английский язык, за исключением комментариев.

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

Синтаксис запросов 1С:Предприятия: "ВЫБРАТЬ ПЕРВЫЕ" и его аналоги

Еще один момент, который вызвал дискуссию, это синтаксис ограничения количества выбираемых записей в языке запросов 1С. Один из пользователей выразил удивление, узнав, что "Выбрать Первые" пишется как Select Top в некоторых диалектах SQL, предполагая, что это должно быть Select First.

Давайте разберемся подробнее. Язык запросов 1С:Предприятия 8 имеет собственный синтаксис, который во многом похож на SQL, но имеет свои особенности. Ключевое слово ВЫБРАТЬ ПЕРВЫЕ в языке запросов 1С используется для ограничения выборки заданным количеством первых записей. Это функционально аналогично операторам, используемым в различных системах управления базами данных (СУБД):

Мы настоятельно рекомендуем всегда использовать ВЫБРАТЬ ПЕРВЫЕ в сочетании с предложением УПОРЯДОЧИТЬ ПО. Почему это так важно? Без явной сортировки порядок возвращаемых записей не гарантируется и может отличаться в разных СУБД или даже при повторном выполнении одного и того же запроса. Использование УПОРЯДОЧИТЬ ПО обеспечивает предсказуемый и стабильный порядок выборки, что критично для корректной работы бизнес-логики.

Посмотрим на пример правильного запроса в 1С:


ВЫБРАТЬ ПЕРВЫЕ 10
    Документ.ПлатежноеПоручениеВходящее.Ссылка
ИЗ
    Документ.ПлатежноеПоручениеВходящее КАК ПлатежноеПоручениеВходящее
ГДЕ
    ПлатежноеПоручениеВходящее.Дата >= &НачалоПериода
УПОРЯДОЧИТЬ ПО
    ПлатежноеПоручениеВходящее.Дата УБЫВ

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

Получение движений документа: разбираемся с отсутствием данных

В ходе обсуждения возникла еще одна важная техническая проблема: почему после получения объекта документа (например, ПлатежноеПоручениеВходящее) с признаком "проведен", его движения (записи в регистрах) оказываются пустыми до момента явного проведения DocObject.Write(DocumentWriteMode.Posting)? Это очень распространенный вопрос у начинающих разработчиков.

Давайте проанализируем ситуацию. Пользователь описывает сценарий:

  1. Выполняется выборка проведенных документов (например, "Платежное поручение входящее") за определенную дату.
  2. Для полученного объекта (у которого стоит признак "проведен") выполняется DocObject = SelectionDetailRecords.Ref.GetObject();.
  3. После этого обращения к свойствам DocObject.Движения.ИмяРегистра показывают, что они пусты.
  4. Движения появляются только после явного вызова DocObject.Write(DocumentWriteMode.Posting);.

Причина такого поведения кроется в оптимизации производительности платформы 1С:Предприятие. Когда мы получаем ссылку на документ (SelectionDetailRecords.Ref) и затем преобразуем ее в объект документа с помощью метода GetObject(), платформа загружает сам объект документа, его реквизиты, табличные части, но НЕ загружает автоматически его движения (записи в регистрах). Свойство Движения объекта документа возвращает объект типа КоллекцияДвижений, которая содержит наборы записей для каждого регистра, по которому данный документ может формировать движения. Однако эти наборы записей изначально пусты.

Для того чтобы получить фактические движения по конкретному регистру, необходимо явно вызвать метод Прочитать() у соответствующего набора записей. Это сделано для того, чтобы избежать избыточной загрузки данных, особенно для документов с большим количеством движений или при работе с большим числом регистров. Загрузка движений "по требованию" позволяет значительно экономить ресурсы и ускорять работу системы, если эти движения не всегда нужны.

Рассмотрим решение проблемы по шагам:

  1. Получаем объект документа.
  2. Для каждого регистра, движения которого нас интересуют, обращаемся к соответствующему набору записей.
  3. Вызываем метод Прочитать() для этого набора записей.

Посмотрим на пример кода, который демонстрирует правильный способ получения движений:


// Предположим, у нас есть ссылка на проведенный документ
// Например, из выборки: SelectionDetailRecords.Ref
СсылкаНаДокумент = SelectionDetailRecords.Ref;

// Получаем объект документа
ОбъектДокумента = СсылкаНаДокумент.GetObject();

// Теперь, чтобы получить движения по конкретному регистру,
// например, по регистру бухгалтерии:
Если ОбъектДокумента.Движения.РегистрБухгалтерии.Доступно() Тогда
    // Если движения по этому регистру могут быть у документа
    ОбъектДокумента.Движения.РегистрБухгалтерии.Прочитать();
    
    // Теперь движения доступны для перебора
    Для Каждого Движение Из ОбъектДокумента.Движения.РегистрБухгалтерии Цикл
        // Обработка каждого движения
        Сообщить("Счет ДТ: " + Движение.СчетДт + ", Счет КТ: " + Движение.СчетКт + ", Сумма: " + Движение.Сумма);
    КонецЦикла;
КонецЕсли;

// Аналогично для других регистров, например, регистра накопления "Взаиморасчеты"
Если ОбъектДокумента.Движения.Взаиморасчеты.Доступно() Тогда
    ОбъектДокумента.Движения.Взаиморасчеты.Прочитать();
    
    Для Каждого Движение Из ОбъектДокумента.Движения.Взаиморасчеты Цикл
        // Обработка движений по взаиморасчетам
        Сообщить("Клиент: " + Движение.Контрагент + ", Сумма: " + Движение.Сумма);
    КонецЦикла;
КонецЕсли;

Метод DocObject.Write(DocumentWriteMode.Posting), который также упоминался, выполняет полное проведение документа с записью всех движений в базу данных. В вашем случае, если документ уже проведен, повторный вызов Write(), по сути, заново формирует и записывает движения, что автоматически делает их доступными в свойстве Движения объекта после этой операции.

Если вам требуется только прочитать движения документа без последующей модификации или перепроведения, более эффективным способом может быть прямой запрос к регистру. Запрос позволяет получить нужные движения напрямую из базы данных, не загружая весь объект документа и не вызывая метод Прочитать() для каждого регистра. Это особенно полезно при работе с большим объемом данных.

Мы надеемся, что эти разъяснения помогут вам лучше понять внутренние механизмы платформы 1С:Предприятие и эффективно решать возникающие задачи разработки.

← На главную