При работе с регистрами бухгалтерии в платформе «1С:Предприятие 8» разработчики иногда сталкиваются с парадоксальной ситуацией: в запросе по виртуальной таблице оборотов или остатков субконто возвращает значение NULL, однако при программном чтении набора записей по регистратору или при просмотре проводок вручную аналитика кажется заполненной.
В этой статье мы подробно проанализируем причины такого поведения системы, разберем типичные ошибки в коде и конфигурации, а также рассмотрим практические способы исправления подобных проблем.
---
Первое, на что необходимо обратить внимание при возникновении расхождений — это соответствие источников данных в запросе и в последующей обработке. Рассмотрим фрагмент кода, аналогичный тому, который часто приводит к недоумению:
Запрос = Новый Запрос;
Запрос.Текст = "
|ВЫБРАТЬ
| НалоговыйОбороты.Счет КАК Счет,
| НалоговыйОбороты.Субконто2 КАК Субконто2,
| НалоговыйОбороты.Регистратор КАК Регистратор
|ИЗ
| РегистрБухгалтерии.Налоговый.Обороты(&НачалоПериода, &КонецПериода, Регистратор) КАК НалоговыйОбороты
|ГДЕ
| НалоговыйОбороты.Субконто2 ЕСТЬ NULL";
РезультатЗапроса = Запрос.Выполнить().Выгрузить();
Для Каждого Движение Из РезультатЗапроса Цикл
Набор = РегистрыБухгалтерии.Хозрасчетный.СоздатьНаборЗаписей();
Набор.Отбор.Регистратор.Установить(Движение.Регистратор);
Набор.Прочитать();
// При анализе Набора мы видим, что Субконто2 заполнено!
КонецЦикла;
Проанализируем эту ситуацию. В запросе получение данных происходит из виртуальной таблицы налогового регистра (РегистрБухгалтерии.Налоговый.Обороты). Именно в налоговом учете по конкретному счету субконто может отсутствовать (возвращается NULL), из-за чего документ-регистратор и попадает в выборку.
Однако внутри цикла выборки создается набор записей для совсем другого регистра — хозрасчетного (бухгалтерского) учета (РегистрыБухгалтерии.Хозрасчетный). Так как налоговый и бухгалтерский регистры — это две разные физические таблицы в СУБД, значения субконто в них могут отличаться. В бухгалтерском учете проводка заполнена полностью, а в налоговом — аналитика пуста. Проверяйте, чтобы в запросе и в коде обработки фигурировал один и тот же регистр.
---
Другая распространенная проблема кроется в понимании того, как платформа позиционирует субконто. В языке запросов поля Субконто1, Субконто2, Субконто3 жестко привязаны к порядку видов субконто, заданному для конкретного счета в Плане счетов конфигурации.
Выясним, как это работает на примере счета 10.10. Предположим, на нем настроены виды субконто в следующем порядке:
Если в запросе мы проверяем условие Субконто2 ЕСТЬ NULL, мы ожидаем увидеть отсутствие Склада. Однако в отладчике при просмотре коллекции Субконто объекта Проводка элементы могут отображаться не по номерам позиций в плане счетов, а по алфавиту названий видов субконто:
В этом случае разработчик визуально видит в отладчике, что "второе" по списку субконто (Партии) заполнено, тогда как в запросе проверялось поле Субконто2 (которое на уровне базы данных соответствует Складу). Чтобы избежать этой путаницы, рекомендуется использовать обращение к субконто в запросах через параметры или виртуальные таблицы с указанием конкретного вида субконто:
// Пример правильного отбора по конкретному виду субконто в запросе
Запрос.Текст = "
|ВЫБРАТЬ
| Обороты.Счет,
| Обороты.Субконто1 КАК Номенклатура
|ИЗ
| РегистрБухгалтерии.Хозрасчетный.Обороты(, , Авто, Счет = &Счет, &ВидыСубконто) КАК Обороты";
МассивСубконто = Новый Массив;
МассивСубконто.Добавить(ПланыВидовХарактеристик.ВидыСубконтоХозрасчетные.Номенклатура);
Запрос.УстановитьПараметр("ВидыСубконто", МассивСубконто);
---
Рассмотрим более сложный сценарий: субконто было физически удалено из счета в Конфигураторе (или был удален сам вид субконто из конфигурации), но в режиме предприятия пользователи продолжают видеть его в некоторых отчетах или проводках.
Когда вы удаляете связь счета с видом субконто в Конфигураторе, платформа 1С перестает проецировать это субконто на позиционные поля виртуальных таблиц (Субконто1...Субконто3). В результате в любых запросах к виртуальным таблицам по этому смещению возвращается NULL.
При этом физические записи в СУБД (таблицы движений регистра бухгалтерии) автоматически не очищаются. В базе данных остаются так называемые "фантомные" или битые ссылки. Метод Прочитать() для набора записей считывает строки напрямую из физической таблицы движений, где эти "удаленные" субконто все еще записаны.
---
Выбор метода решения зависит от того, нужно ли вам восстановить удаленную аналитику или полностью очистить базу от некорректных записей.
Если субконто было удалено ошибочно, верните его настройки на счет в Конфигураторе. После этого самым простым и безопасным способом восстановить движения является перепроведение документов-регистраторов. При проведении модуль документа заново сформирует движения по актуальным правилам конфигурации, затерев старые некорректные записи.
Если перепроведение документов в закрытом периоде невозможно или нежелательно, воспользуйтесь встроенными утилитами платформы. Выполните тестирование и исправление информационной базы (обязательно на резервной копии!):
Платформа просканирует таблицы итогов и движений регистра бухгалтерии, удалит потерянные связи и очистит некорректные записи субконто в физических таблицах базы данных.
В случаях, когда ТИИ не помогает, можно написать внешнюю обработку для точечной очистки или заполнения субконто без изменения других реквизитов проводки и без перепроведения документа. Рассмотрим пример кода:
// Программное заполнение пропавшего субконто Склад в Хозрасчетном регистре
Набор = РегистрыБухгалтерии.Хозрасчетный.СоздатьНаборЗаписей();
Набор.Отбор.Регистратор.Установить(СсылкаНаДокумент);
Набор.Прочитать();
Для Каждого Проводка Из Набор Цикл
Если Проводка.СчетДт = ПланыСчетов.Хозрасчетный.ТоварыНаСкладах Тогда
// Устанавливаем значение субконто напрямую по имени вида субконто
Проводка.СубконтоДт[ПланыВидовХарактеристик.ВидыСубконтоХозрасчетные.Склады] = НужныйСклад;
КонецЕсли;
КонецЦикла;
// Записываем набор с флагом ОбменДанными.Загрузка, чтобы обойти проверки проведения
Набор.ОбменДанными.Загрузка = Истина;
Набор.Записать();
Использование свойства ОбменДанными.Загрузка = Истина позволяет перезаписать движения регистра напрямую, не вызывая повторное проведение документа и сохраняя неизменными остальные данные учета.