Tool1CD: отрежем донорскую почку

Ваша база мертва? Что ж, кое-что в ней ещё теплится.

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

Сценарий из жизни: розничная сеть, РИБ, кассовые узлы раз в месяц где-нибудь да сломаются, данные по последним продажам не попадают в центральный узел. Как мы решали проблему тогда? Поддержка копирует файл базы из магазина в офис, я с помощью старой доброй Tool1CD выгружаю таблицы с данными о чеках, глазами смотрю, чего не достаёт, руками редактирую выгрузку и запускаю костыль в виде обработки загрузки. Сейчас, имея на руках новый, подключаемый вариант библиотеки, я бы поступил по-другому. Новый сценарий: поддержка копирует файл базы себе на компьютер, запускает в 1С в центральном узле обработку, в обработке выбирает файл базы, нажимает большую волшебную кнопку "Вжух!" и нужные данные появляются в базе. Без моего участия, совсем. Вот таким образом мне нравится делать свою работу! Давайте попробуем сделать такую обработку.

Открываем предыдущую статью, выполняем "Часть 0" и только после этого идём дальше.

Что же должна делать обработка под капотом? Алгоритм следующий:

  • Открываем базу
  • Определяем принадлежность узла
  • Получаем список чеков в базе узла
  • Сравниваем с чеками в текущей базе — выделяем список недостающих
  • По списку запрашиваем данные из базы узла

В качестве упрощения нам дано то, что все узлы созданы путём копирования базы шаблона, потому мы заранее знаем соответствие метаданных и таблиц. Сведения о моей базе:

  • _NODE17 — план обмена По Кассе, поле _FLD254RREF — Касса. Отсюда узнаём, откуда база.
  • _DOCUMENT122 — Чек ККМ. Отсюда тащим недостающие данные.

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

Работа на стороне 1С останется за кадром, здесь мы будем рассматривать только то , что касается непосредственно функционала tool1cd.

Исходя из алгоритма API нашей компоненты должен выглядеть как-то так:

  • ОткрытьБазу / OpenDatabase. Принимает параметр — путь к базе. Возвращает 0, если база открыта, или код ошибки.
  • ОпределитьПринадлежностьУзла / GetNodeIdentity. Принимает параметры — имя таблицы плана обмена и имя поля с кассой. Возвращает строку — GUID кассы ККМ.
  • ПолучитьСписокДокументов / GetDocumentList. Принимает параметр — имя таблицы. Возвращает строку — список GUID через запятую.
  • ПолучитьДанныеПоДокументу / GetDocumentData. Принимает параметры — имя таблицы и GUID документа. Возвращает строку — XML представление документа.
  • ЗакрытьБазу / CloseDatabase. Закрывает открытую базу.

 

Псевдокод на 1С:

 

 Процедура ОбработатьУзел

Начнём с простого

Создадим методы ОткрытьБазу и ЗакрытьБазу. Как в первой статье каждую процедуру и функцию я буду добавлять путём копирования сигнатуры CallAsProc или CallAsFunc и перенаправления вызова, обёрнутого в try/catch, также опуская все остальные необходимые формальности.

Потому как мы работаем с базой не за один заход и нам нужно хранить состояние (открытую базу), то нам необходимо добавить поле T_1CD *db в объявление класса:

 

 class CAddInNative

За исключением обработки tVariant код методов крайне прост:

 

 CAddInNative::OpenDatabase

 

 CAddInNative::CloseDatabase

 

Пробежимся по записям

Итак, базу мы открыли, теперь надо определить её принадлежность. Мы знаем имя таблицы, надо её найти, обойти, найти нужную запись и получить значение поля. Для начала введём вспомогательную функцию, которая будет обрабатывать параметр-строку:

 

extract_string

Находим таблицу, находим в ней запись c заполненным _PREDEFINEDID — это ЭтотУзел в плане обмена.

 
 

 CAddInNative::GetNodeIdentity

В приведённом выше коде глаз должен зацепиться за два момента:

  1. Мы ищем таблицу по имени циклом — кто первый пришлёт патч, а?
  2. Конструкция get<BinaryGuid>. BinaryGuid — класс, специально для работы с GUID-ами в файловой базе. Основных задач у него всего две — взять данные из базы и преобразовать их в строку и наоборот — получить строку и преобразовать её в двоичный вид. Напомню очень хорошую статью про GUID — она обязательна к ознакомлению перед просмотром исходников BinaryGuid.

 

Получим список документов. Ничего нового — ищем таблицу, перебираем записи итератором, формируем строку из GUID-ов.

 

 CAddInNative::GetDocumentList

 

Получение данных по документу.

Для начала надо составить список таблиц, в которых хранятся данные документа. Это основная таблица документа (_DOCUMENT122) и табличные части (_DOCUMENT122_VT*). Также стоит отметить, что в табличных частях поле Ссылка имеет имя не _IDREF, а _DOCUMENT122_IDREF.

 
 

CAddInNative::GetDocumentData

Вспомогательная процедура по выводу полей:

 

 store_record_to_stream

В коде процедуры обратим внимание на два момента:

  1. Проверка is_null_value. Нельзя так просто взять и получить значение поля, которое null — будет выброшено исключение.
  2. get_xml_string — любезно заранее подготовленная функция, которая возвращает строковое представление значения, которое можно просто взять и запихнуть в XML.

На выходе получаем текст XML, подобный следующему:

 

Пример получаемого XML-файла

Уверен, загрузить такого вида XML не составит большого труда, потому расписывать здесь парсер нет никакого смысла.

Что дальше?

Если у вас есть какие-то интересные случаи, которые можно было бы разобрать — пишите в комментариях, обсудим.

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

13 Comments

  1. nporrep

    Шикарный материал.

    На подобном уровне должен бы существовать инструмент по программному созданию объектов метаданных конфигурации + внешних отчетов/обработок.

    Например, для сборки файла внешней печатной формы с заполненными по шаблону предопределенными процедурами и приёмами БСП-кидо.

    Обработка для программного создания обработок… Программное создание форм по описаниями…. Программное создание регистров по описаниям.

    Каждый из 1С-разработчиков быстро нашёл бы способ собрать себе собственную палитру шаблонов кода / описаний МД, чтобы затем на этом уровне программном прослойки делать рутинную работу максимально быстро и максимально привычными способами.

    Reply
  2. baton_pk

    (1)

    На подобном уровне должен бы существовать инструмент по программному созданию объектов метаданных конфигурации + внешних отчетов/обработок.

    надеюсь, скоро для этого будет хватать штатных возможностей конфигуратора/EDT. Без участия внешних костылей.

    Tool1CD — он всё же про то, когда 1С уже не может.

    Reply
  3. nporrep

    (2) Любая IDEшка так или иначе навязывает приемы разработки разработчику, иногда полезные, иногда не очень.

    Спросите у адептов Eclipse, удобно ли им работать в JetBrains, на совсем чужих «быстрых клавишах», например =)

    А ведь у EDT ноги из того же JetBrains’а растут…

    Проблема ещё и в проприетарности не только кода платформы, но и форматов файлов конфигурации и внешних обработов/отчеботок.

    А за попытки расковырять эти самые форматы ребята в жёлтых майках бьют по пальцам железной линейкой с фирменным логотипом…

    Reply
  4. Infactum

    (3) Форматы уже давно все расковыряли. Да, есть кое-где белые пятна, но это не мешает. То, что информация не публикуется конкретно на этом портале — это уже вопрос к политике инфостарта.

    EDT никак не связано с JetBrains. Оно на eclipse основано.

    1С похоже денег пожалели на то, чтобы реальных профессионалов нанять в разработке IDE.

    Reply
  5. nytlenc

    Самому не уверен что пригодится, но!!! За идею и ее реализацию однозначно 5.

    Reply
  6. bulpi

    «Уверен, загрузить такого вида XML не составит большого труда, потому расписывать здесь парсер нет никакого смысла.»

    Не понял. А через ПрочитатьXML он не прочтется ? А почему ?

    Reply
  7. baton_pk

    (6)

    Не понял. А через ПрочитатьXML он не прочтется ? А почему ?

    потому что сериализатор 1С ничего не знает про эти _FLD12345. Потому всё равно нужен код вида:

    СтрокаТаблицы.Номенклатура = Справочники.Номенклатура.ПолучитьСсылку(Новый УникальныйИдентификатор(ХМЛ._FLD12345));

    Reply
  8. nporrep

    (4) Я давно далек от таких подробностей, хотя и иногда ностальгирую по тем временам.

    Егор, Вы взялись бы реализовать задачу, описанную в (1)?

    Reply
  9. nporrep

    (9) Детишки, ну не занимайтесь ерундой, на карме скажется больше, чем на кошельке отразится =)

    Reply
  10. kuntashov

    (1)

    Например, для сборки файла внешней печатной формы с заполненными по шаблону предопределенными процедурами и приёмами БСП-кидо.

    Если я вас правильно понял, то давно уже есть, правда сделано на базе альтернативного распаковщика/запаковщика, см. статью https://infostart.ru/public/454827/

    На его базе в том числе сделан онлайн-сервис для генерации шаблонов ВПФ для БСП:

    http://www.develplatform.ru/OneC/Online-instruments/CEDP

    Reply
  11. logarifm

    Отличный материал. Но насчет сейчас. Вот какраз-таки сейчас у 1с есть отличная вещь как сервер на несколько рабочих мест. Вполне хватает мне для магазинов, а их у меня больше 50. Везде стоят СКЛ експресы и подобной ситуации по вылету нет. Да и базы намного шустрее!

    Reply
  12. baton_pk

    (12) базы ломаются у разных контор разных размеров и формата деятельности.

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

    Reply
  13. tezdal

    (12) Сервер это клевая затея, но у нас по формату сети в магазине чаще всего 1 касса, нет компьютера администратора и прочего. есть супервайзеры ответственные за свой сегмент, вот у них мобильный офис на колесах в машине организован. Если касс в магазине => 2 тогда никто не подпишет смету на сервер. поэтому и приходится вертеться)

    Reply

Leave a Comment

Ваш адрес email не будет опубликован. Обязательные поля помечены *