При разработке сложных учетных механизмов в 1С:Предприятии 7.7 стандартных средств системы иногда оказывается недостаточно, особенно когда требуется высокая производительность при проведении документов задним числом. Использование библиотеки 1С++ позволяет обращаться к данным базы напрямую через SQL-запросы. Однако при переходе от SQL-версии к файловой (DBF) возникают существенные различия в реализации. Давайте разберем, как правильно организовать получение остатков в DBF-базах.
Основное отличие между SQL-версией и файловой версией при работе с 1С++ заключается в способе доступа к данным регистра. В SQL-версии мы можем использовать специализированные конструкции метаданных, такие как $РегистрОстатки. В DBF-версии такие конструкции недоступны, так как парсер библиотеки не может автоматически объединять разрозненные таблицы итогов и движений.
Для DBF-базы нам необходимо самостоятельно построить логику запроса, которая будет:
$РегистрИтоги на начало периода.$Регистр за период с начала месяца до момента времени нужного документа.debkred.Чтобы получить актуальные остатки товаров на момент проведения документа, мы создадим универсальную функцию. Важно учитывать, что при прямом доступе к DBF-файлам через OLEDB необходимо управлять блокировками и буферизацией данных.
Ниже представлен пример кода, который объединяет накопленные итоги и текущие движения:
Функция ПолучитьОстаткиДокПр(ТекДок) Экспорт
Если МонопольныйРежим=1 Тогда Возврат 0; КонецЕсли;
Попытка
База = СоздатьОбъект("OLEDBData");
Соединение =" |Provider=VFPOLEDB.1; |Data Source=" + КаталогИБ + "; |Mode=Read; |";
Рез = База.Соединение(Соединение);
Запрос = База.СоздатьКоманду;
Исключение Возврат 0; КонецПопытки;
// Установка параметров соединения для стабильной работы
Запрос.Выполнить("EXECSCRIPT('SET ANSI OFF')");
Запрос.Выполнить("EXECSCRIPT('SET REPROCESS TO 60 SECONDS')");
Запрос.Выполнить("EXECSCRIPT('SET REFRESH TO 0,-1')");
Запрос.Выполнить("Exec('SET TABLEVALIDATE TO 0')");
ТекстЗапроса = "
|SELECT
| Рег.Товар as [Товар $Справочник.Каталог],
| SUM(Рег.Количество) as Количество,
| SUM(Рег.Сумма) as Сумма,
| SUM(Рег.СуммаВалюта) as СуммаВалюта
|FROM (
| SELECT
| $Р.Товар AS Товар,
| $Р.Количество AS Количество,
| $Р.Сумма AS Сумма,
| $Р.СуммаВалюта AS СуммаВалюта
| FROM $РегистрИтоги.Товары as Р
| WHERE (period = :ПредМесяц~~) AND ($Р.Склад=:Склад)
| UNION ALL
| SELECT
| $Р.Товар AS Товар,
| $Р.Количество * (1 - Р.debkred * 2) AS Количество,
| $Р.Сумма * (1 - Р.debkred * 2) AS Сумма,
| $Р.СуммаВалюта * (1 - Р.debkred * 2) AS СуммаВалюта
| FROM $Регистр.Товары AS Р
| INNER JOIN 1sjourn jr ON Р.iddoc = jr.iddoc
| AND (DTOS(jr.date)+jr.time+jr.iddoc BETWEEN :НачалоМесяца AND :ПредДата~)
| WHERE ($Р.Склад=:Склад)
|) AS Рег
|GROUP BY Рег.Товар";
Запрос.УстановитьТекстовыйПараметр("Склад", ТекДок.Склад);
Запрос.УстановитьТекстовыйПараметр("ПредДата", СформироватьПозициюДокумента(ТекДок, -1));
Запрос.УстановитьТекстовыйПараметр("НачалоМесяца", начМесяца(ТекДок.ДатаДок));
Запрос.УстановитьТекстовыйПараметр("ПредМесяц", начМесяца(начМесяца(ТекДок.ДатаДок)-1));
ТЗ = Запрос.ВыполнитьИнструкцию(ТекстЗапроса);
Возврат ТЗ;
КонецФункции
При анализе данного кода обратите внимание на следующие важные моменты, которые обеспечивают корректный расчет:
(1 - Р.debkred * 2) — это математический трюк. Поскольку в 7.7 приход хранится с debkred = 0, а расход с debkred = 1, эта формула превращает приход в положительное число, а расход — в отрицательное. Это позволяет нам просто просуммировать все записи с помощью SUM().DirectQuery в 7.7.SET REPROCESS и SET REFRESH критически важны в многопользовательской среде. Они предотвращают ошибки доступа к файлам DBF, если в момент выполнения запроса другие пользователи проводят свои документы.СформироватьПозициюДокумента используется для получения точного момента времени (дата, время, ID документа), что позволяет нам рассчитать остатки ровно на секунду перед началом проведения текущего документа.Используя этот подход, вы сможете эффективно получать остатки товаров непосредственно в модуле проведения, что критически важно при реализации собственной логики списания по балансовой стоимости.