Рассмотрим очередной пример использования библиотеки tool1d. Сейчас мы напишем программку, которая облегчила бы мне жизнь пару лет назад.
Сценарий из жизни: розничная сеть, РИБ, кассовые узлы раз в месяц где-нибудь да сломаются, данные по последним продажам не попадают в центральный узел. Как мы решали проблему тогда? Поддержка копирует файл базы из магазина в офис, я с помощью старой доброй Tool1CD выгружаю таблицы с данными о чеках, глазами смотрю, чего не достаёт, руками редактирую выгрузку и запускаю костыль в виде обработки загрузки. Сейчас, имея на руках новый, подключаемый вариант библиотеки, я бы поступил по-другому. Новый сценарий: поддержка копирует файл базы себе на компьютер, запускает в 1С в центральном узле обработку, в обработке выбирает файл базы, нажимает большую волшебную кнопку "Вжух!" и нужные данные появляются в базе. Без моего участия, совсем. Вот таким образом мне нравится делать свою работу! Давайте попробуем сделать такую обработку.
Открываем предыдущую статью, выполняем "Часть 0" и только после этого идём дальше.
Что же должна делать обработка под капотом? Алгоритм следующий:
- Открываем базу
- Определяем принадлежность узла
- Получаем список чеков в базе узла
- Сравниваем с чеками в текущей базе — выделяем список недостающих
- По списку запрашиваем данные из базы узла
В качестве упрощения нам дано то, что все узлы созданы путём копирования базы шаблона, потому мы заранее знаем соответствие метаданных и таблиц. Сведения о моей базе:
- _NODE17 — план обмена По Кассе, поле _FLD254RREF — Касса. Отсюда узнаём, откуда база.
- _DOCUMENT122 — Чек ККМ. Отсюда тащим недостающие данные.
Сведения о вашей базе можете получить через функцию глобального контекста 1С ПолучитьСтруктуруХраненияБазыДанных или через множество обработок на её основе, которые можно найти на Инфостарте.
Работа на стороне 1С останется за кадром, здесь мы будем рассматривать только то , что касается непосредственно функционала tool1cd.
Исходя из алгоритма API нашей компоненты должен выглядеть как-то так:
- ОткрытьБазу / OpenDatabase. Принимает параметр — путь к базе. Возвращает 0, если база открыта, или код ошибки.
- ОпределитьПринадлежностьУзла / GetNodeIdentity. Принимает параметры — имя таблицы плана обмена и имя поля с кассой. Возвращает строку — GUID кассы ККМ.
- ПолучитьСписокДокументов / GetDocumentList. Принимает параметр — имя таблицы. Возвращает строку — список GUID через запятую.
- ПолучитьДанныеПоДокументу / GetDocumentData. Принимает параметры — имя таблицы и GUID документа. Возвращает строку — XML представление документа.
- ЗакрытьБазу / CloseDatabase. Закрывает открытую базу.
Псевдокод на 1С:
Процедура ОбработатьУзел(Знач ПутьКБазе)
ПутьККомпоненте = "C:...VNCOMPSVNCOMP83exampleinRelWithDebInfoAddInNativeWin32.dll";
Если Не ПодключитьВнешнююКомпоненту(ПутьККомпоненте, "CDReader", ТипВнешнейКомпоненты.Native) Тогда
Сообщить("Ошибочка");
Возврат;
КонецЕсли;
Читалка = Новый("AddIn.CDReader.AddInNativeExtension");
Читалка.ОткрытьБазу(ПутьКБазе);
// не зашиваем имена таблиц в компоненту во имя гибкости
КассаИд = Читалка.ОпределитьПринадлежностьУзла("_NODE17", "_FLD254RREF");
Касса = Справочники.Кассы.ПолучитьСсылку(Новый УникальныйИдентификатор(КассаИд));
СписокДокументов = Читалка.ПолучитьСписокДокументов("_DOCUMENT122");
СписокДокументов = СтрРазделить(СписокДокументов, ",");
// преобразуем гуиды в ссылки
Для Инд = 0 По СписокДокументов.Количество() - 1 Цикл
УИД = Новый УникальныйИдентификатор(СписокДокументов[Инд]);
СписокДокументов[Инд] = Документы.ЧекККМ.ПолучитьСсылку(УИД);
КонецЦикла;
СписокНедостающих = ОпределитьСписокНедостающих(Касса, СписокДокументов);
Для Каждого мСсылка Из СписокНедостающих Цикл
ГУИД = Строка(мСсылка.УникальныйИдентификатор());
Сообщить(ГУИД);
Данные = Читалка.ПолучитьДанныеПоДокументу("_DOCUMENT122", ГУИД);
ДобавитьДокументВБазу(Данные);
КонецЦикла;
Читалка.ЗакрытьБазу();
КонецПроцедуры
Начнём с простого
Создадим методы ОткрытьБазу и ЗакрытьБазу. Как в первой статье каждую процедуру и функцию я буду добавлять путём копирования сигнатуры CallAsProc или CallAsFunc и перенаправления вызова, обёрнутого в try/catch, также опуская все остальные необходимые формальности.
Потому как мы работаем с базой не за один заход и нам нужно хранить состояние (открытую базу), то нам необходимо добавить поле T_1CD *db в объявление класса:
// ...
#include <Class_1CD.h> // <<-- вот оно
// ...
class CAddInNative : public IComponentBase
{
public:
enum Props{...};
enum Methods{...};
CAddInNative(void);
virtual ~CAddInNative();
// ...
private:
// ...
T_1CD *db; // <<-- и вот
};
За исключением обработки tVariant код методов крайне прост:
CAddInNative::OpenDatabase
bool ADDIN_API CAddInNative::OpenDatabase(const long lMethodNum, tVariant* pvarRetValue, tVariant* paParams, const long lSizeArray)
{
boost::filesystem::path filepath;
// переделанный кусок кода из eMethLoadPicture
{
if (!lSizeArray || !paParams)
return false;
switch (TV_VT(paParams))
{
case VTYPE_PSTR:
filepath = boost::filesystem::path(std::string(paParams->pstrVal));
break;
case VTYPE_PWSTR:
{
wchar_t *wsTmp = nullptr;
::convFromShortWchar(&wsTmp, TV_WSTR(paParams));
filepath = boost::filesystem::path(std::wstring(wsTmp));
delete[] wsTmp;
break;
}
default:
return false;
}
}
db = new T_1CD(filepath);
TV_VT(pvarRetValue) = VTYPE_I4;
if (db->is_open() && db->is_infobase()) {
TV_I4(pvarRetValue) = 0;
}
else {
TV_I4(pvarRetValue) = 2; // код ошибки
}
return true;
}
CAddInNative::CloseDatabase
bool ADDIN_API CAddInNative::CloseDatabase(const long lMethodNum, tVariant * paParams, const long lSizeArray)
{
delete db;
db = nullptr;
return true;
}
Пробежимся по записям
Итак, базу мы открыли, теперь надо определить её принадлежность. Мы знаем имя таблицы, надо её найти, обойти, найти нужную запись и получить значение поля. Для начала введём вспомогательную функцию, которая будет обрабатывать параметр-строку:
std::string extract_string(const tVariant ¶m)
{
switch (TV_VT(¶m))
{
case VTYPE_PSTR:
return std::string(param.pstrVal, param.strLen);
case VTYPE_PWSTR:
{
uint8_t * data = reinterpret_cast<uint8_t*>(param.pwstrVal);
int size_in_bytes = param.wstrLen * sizeof(WCHAR_T);
std::vector<uint8_t> decode_vector;
decode_vector.assign(data, data + size_in_bytes);
return System::SysUtils::TEncoding::Unicode->toUtf8(decode_vector);
}
default:
throw std::exception("Передали не строку");
}
}
Находим таблицу, находим в ней запись c заполненным _PREDEFINEDID — это ЭтотУзел в плане обмена.
CAddInNative::GetNodeIdentity
bool ADDIN_API CAddInNative::GetNodeIdentity(const long lMethodNum, tVariant * pvarRetValue, tVariant * paParams, const long lSizeArray)
{
std::string table_name = extract_string(paParams[0]);
std::string field_name = extract_string(paParams[1]);
for (int i = 0; i < db->get_numtables(); i++) {
// ищем указанную таблицу
Table *t = db->get_table(i);
if (!System::EqualIC(table_name, t->get_name())) {
continue;
}
// нашли - обрабатываем
// для плана обмена нам нужен узел, у которого заполнен PREDEFINED_ID
TableIterator it(t);
while (!it.eof()) {
BinaryGuid predefined_id = it.current().get<BinaryGuid>("_PREDEFINEDID");
if (!predefined_id.is_empty()) {
// нашли нужный узел!
// берём гуид кассы и возвращаем
BinaryGuid kassa_guid = it.current().get<BinaryGuid>(field_name);
std::string utf8result = kassa_guid.as_1C();
// во имя кроссплатформенности, нужно перевести его в utf-16
std::vector<uint8_t> result = System::SysUtils::TEncoding::Unicode->fromUtf8(utf8result);
m_iMemory->AllocMemory((void**)&pvarRetValue->pwstrVal, result.size());
memcpy((void*)pvarRetValue->pwstrVal, result.data(), result.size());
TV_VT(pvarRetValue) = VTYPE_PWSTR;
pvarRetValue->wstrLen = result.size() / sizeof(WCHAR_T);
return true;
}
it.next();
}
}
// Сюда приходим, если не нашли таблицу или узел
TV_VT(pvarRetValue) = VTYPE_I4;
TV_I4(pvarRetValue) = 3;
return true;
}
В приведённом выше коде глаз должен зацепиться за два момента:
- Мы ищем таблицу по имени циклом — кто первый пришлёт патч, а?
- Конструкция get<BinaryGuid>. BinaryGuid — класс, специально для работы с GUID-ами в файловой базе. Основных задач у него всего две — взять данные из базы и преобразовать их в строку и наоборот — получить строку и преобразовать её в двоичный вид. Напомню очень хорошую статью про GUID — она обязательна к ознакомлению перед просмотром исходников BinaryGuid.
Получим список документов. Ничего нового — ищем таблицу, перебираем записи итератором, формируем строку из GUID-ов.
CAddInNative::GetDocumentList
bool ADDIN_API CAddInNative::GetDocumentList(const long lMethodNum, tVariant * pvarRetValue, tVariant * paParams, const long lSizeArray)
{
std::string table_name = extract_string(paParams[0]);
std::string utf8result;
for (int i = 0; i < db->get_numtables(); i++) {
Table *t = db->get_table(i);
if (!System::EqualIC(table_name, t->get_name())) {
continue;
}
TableIterator it(t);
while (!it.eof()) {
if (!utf8result.empty()) {
utf8result.append(",");
}
BinaryGuid guid = it.current().get<BinaryGuid>("_IDRREF");
utf8result.append(guid.as_1C());
it.next();
}
// во имя кроссплатформенности, нужно перевести результат в utf-16
std::vector<uint8_t> result = System::SysUtils::TEncoding::Unicode->fromUtf8(utf8result);
m_iMemory->AllocMemory((void**)&pvarRetValue->pwstrVal, result.size());
memcpy((void*)pvarRetValue->pwstrVal, result.data(), result.size());
TV_VT(pvarRetValue) = VTYPE_PWSTR;
pvarRetValue->wstrLen = result.size() / sizeof(WCHAR_T);
return true;
}
// Сюда приходим, если не нашли таблицу
TV_VT(pvarRetValue) = VTYPE_I4;
TV_I4(pvarRetValue) = 3;
return true;
}
Получение данных по документу.
Для начала надо составить список таблиц, в которых хранятся данные документа. Это основная таблица документа (_DOCUMENT122) и табличные части (_DOCUMENT122_VT*). Также стоит отметить, что в табличных частях поле Ссылка имеет имя не _IDREF, а _DOCUMENT122_IDREF.
CAddInNative::GetDocumentData
bool ADDIN_API CAddInNative::GetDocumentData(const long lMethodNum, tVariant * pvarRetValue, tVariant * paParams, const long lSizeArray)
{
std::string table_name = extract_string(paParams[0]);
BinaryGuid doc_id = BinaryGuid(extract_string(paParams[1]));
std::stringstream utf8result;
std::string derived_mask = table_name + "_VT";
std::string derived_key_field = table_name + "_IDRREF";
// ищем основную таблицу документа и табличные части
Table *main_table = nullptr;
std::vector<Table *> derived_tables;
for (int i = 0; i < db->get_numtables(); i++) {
Table *t = db->get_table(i);
std::string current_table_name = t->get_name();
if (System::EqualIC(table_name, current_table_name)) {
main_table = t;
}
if (current_table_name.size() < derived_mask.size()) {
continue;
}
if (System::EqualIC(current_table_name.substr(0, derived_mask.size()), derived_mask)) {
// это таблиная часть
derived_tables.push_back(t);
}
}
if (main_table == nullptr) {
TV_VT(pvarRetValue) = VTYPE_I4;
TV_I4(pvarRetValue) = 3;
return true;
}
TableIterator it(main_table);
while (!it.eof()) {
if (it.current().get<BinaryGuid>("_IDRREF") != doc_id) {
it.next();
continue;
}
// нашли нужную запись - выводим
utf8result << "<" << table_name << ">";
store_record_to_stream(utf8result, main_table, it.current());
// теперь ищем записи в подчинённых таблицах
for (Table *derived : derived_tables) {
utf8result << "<" << derived->get_name() << ">";
TableIterator dit(derived);
while (!dit.eof()) {
if (dit.current().get<BinaryGuid>(derived_key_field) == doc_id) {
utf8result << "<record>";
store_record_to_stream(utf8result, derived, dit.current());
utf8result << "</record>";
}
dit.next();
}
utf8result << "</" << derived->get_name() << ">";
}
utf8result << "</" << table_name << ">";
break;
}
// во имя кроссплатформенности, нужно перевести результат в utf-16
std::vector<uint8_t> result = System::SysUtils::TEncoding::Unicode->fromUtf8(utf8result.str());
m_iMemory->AllocMemory((void**)&pvarRetValue->pwstrVal, result.size());
memcpy((void*)pvarRetValue->pwstrVal, result.data(), result.size());
TV_VT(pvarRetValue) = VTYPE_PWSTR;
pvarRetValue->wstrLen = result.size() / sizeof(WCHAR_T);
return true;
}
Вспомогательная процедура по выводу полей:
void store_record_to_stream(std::stringstream &str, Table *t, const TableRecord &record)
{
for (int field_num = 0; field_num < t->get_num_fields(); field_num++) {
Field *f = t->get_field(field_num);
if (record.is_null_value(f)) {
str << "<" << f->get_name() << "/>";
}
else {
str << "<" << f->get_name() << ">";
str << record.get_xml_string(f);
str << "</" << f->get_name() << ">";
}
}
}
В коде процедуры обратим внимание на два момента:
- Проверка is_null_value. Нельзя так просто взять и получить значение поля, которое null — будет выброшено исключение.
- get_xml_string — любезно заранее подготовленная функция, которая возвращает строковое представление значения, которое можно просто взять и запихнуть в XML.
На выходе получаем текст XML, подобный следующему:
Пример получаемого XML-файла
<_DOCUMENT122>
<_IDRREF>dc0a6b43-5503-11e8-9479-cdce35f4f3fd</_IDRREF>
<_VERSION>1:0:10:0</_VERSION>
<_MARKED>false</_MARKED>
<_DATE_TIME>2024-05-11T13:30:55</_DATE_TIME>
<_NUMBERPREFIX>2024-01-01T00:00:00</_NUMBERPREFIX>
<_NUMBER>ALMM0000001</_NUMBER>
<_POSTED>true</_POSTED>
<_FLD1857RREF>4be07a6a-8b6c-4ee4-a4fe-edd07da60d48</_FLD1857RREF>
<_FLD1858_TYPE>01 </_FLD1858_TYPE>
<_FLD1858_RTREF>00000000 </_FLD1858_RTREF>
<_FLD1858_RRREF>00000000-0000-0000-0000-000000000000</_FLD1858_RRREF>
<_FLD1859RREF>00000000-0000-0000-0000-000000000000</_FLD1859RREF>
<_FLD1860RREF>3c0ad32a-4511-11e2-a517-0026554acea0</_FLD1860RREF>
<_FLD1861></_FLD1861>
<_FLD1862>1</_FLD1862>
<_FLD1863>1</_FLD1863>
<_FLD1864RREF>3ba3683e-f136-11e3-9402-d89d671cc0a3</_FLD1864RREF>
<_FLD1865>12460</_FLD1865>
<_FLD1866RREF>355d3a67-f60e-11e3-9407-ac162d728dbf</_FLD1866RREF>
<_FLD1867RREF>00000000-0000-0000-0000-000000000000</_FLD1867RREF>
<_FLD1868RREF>00000000-0000-0000-0000-000000000000</_FLD1868RREF>
<_FLD1869RREF>00000000-0000-0000-0000-000000000000</_FLD1869RREF>
<_FLD1870RREF>d45671c8-4420-48aa-89f5-7af1607d02e3</_FLD1870RREF>
<_FLD1871RREF>00000000-0000-0000-0000-000000000000</_FLD1871RREF>
<_FLD1872RREF>00000000-0000-0000-0000-000000000000</_FLD1872RREF>
<_FLD1873RREF>00000000-0000-0000-0000-000000000000</_FLD1873RREF>
<_FLD1874></_FLD1874>
<_FLD1875RREF>00000000-0000-0000-0000-000000000000</_FLD1875RREF>
<_FLD1876>false</_FLD1876>
<_FLD1877RREF>00000000-0000-0000-0000-000000000000</_FLD1877RREF>
<_FLD1878>0</_FLD1878>
<_FLD1879>0-00-00T00:00:00</_FLD1879>
<_FLD1880>2024-05-11T13:30:55</_FLD1880>
<_FLD1881>0</_FLD1881>
<_FLD1882></_FLD1882>
<_FLD1883>false</_FLD1883>
<_FLD1884>false</_FLD1884>
<_FLD3387RREF>00000000-0000-0000-0000-000000000000</_FLD3387RREF>
<_FLD3388></_FLD3388>
<_FLD3389></_FLD3389>
<_FLD3390></_FLD3390>
<_FLD3391></_FLD3391>
<_FLD3392>0</_FLD3392>
<_FLD3393RREF>00000000-0000-0000-0000-000000000000</_FLD3393RREF>
<_FLD3394>0</_FLD3394>
<_FLD3395></_FLD3395>
<_FLD3396RREF>00000000-0000-0000-0000-000000000000</_FLD3396RREF>
<_FLD3397>0</_FLD3397>
<_FLD3517RREF>00000000-0000-0000-0000-000000000000</_FLD3517RREF>
<_FLD4224>0</_FLD4224>
<_FLD4225RREF>00000000-0000-0000-0000-000000000000</_FLD4225RREF>
<_FLD4226></_FLD4226>
<_FLD4293>456</_FLD4293>
<_FLD4294></_FLD4294>
<_FLD4295>123</_FLD4295>
<_DOCUMENT122_VT1885>
<record>
<_DOCUMENT122_IDRREF>dc0a6b43-5503-11e8-9479-cdce35f4f3fd</_DOCUMENT122_IDRREF>
<_KEYFIELD>00000002 </_KEYFIELD>
<_LINENO1886>2</_LINENO1886>
<_FLD1887RREF>3646e7f8-2c0d-11df-af1f-00215a763825</_FLD1887RREF>
<_FLD1888RREF>00000000-0000-0000-0000-000000000000</_FLD1888RREF>
<_FLD4188RREF>00000000-0000-0000-0000-000000000000</_FLD4188RREF>
<_FLD1889>1</_FLD1889>
<_FLD1890RREF>3646e7f9-2c0d-11df-af1f-00215a763825</_FLD1890RREF>
<_FLD1891>1</_FLD1891>
<_FLD1892>6480</_FLD1892>
<_FLD1893>6480</_FLD1893>
<_FLD1894RREF>8ab98fd8-943a-451a-98e5-973d4b7617e8</_FLD1894RREF>
<_FLD1895>988.47</_FLD1895>
<_FLD1896>0</_FLD1896>
<_FLD1897>0</_FLD1897>
<_FLD1898RREF>00000000-0000-0000-0000-000000000000</_FLD1898RREF>
<_FLD1899_TYPE>01 </_FLD1899_TYPE>
<_FLD1899_N>0</_FLD1899_N>
<_FLD1899_RTREF>00000000 </_FLD1899_RTREF>
<_FLD1899_RRREF>00000000-0000-0000-0000-000000000000</_FLD1899_RRREF>
<_FLD1900>false</_FLD1900>
<_FLD1901>2000000012124</_FLD1901>
<_FLD1902RREF>185600fa-b094-11e1-a511-0026554acea0</_FLD1902RREF>
<_FLD1903>2</_FLD1903>
<_FLD1904RREF>00000000-0000-0000-0000-000000000000</_FLD1904RREF>
<_FLD1905>false</_FLD1905>
<_FLD1906>false</_FLD1906>
<_FLD1907>0-00-00T00:00:00</_FLD1907>
<_FLD2758>false</_FLD2758>
<_FLD2759>0</_FLD2759>
<_FLD2760RREF>00000000-0000-0000-0000-000000000000</_FLD2760RREF>
<_FLD3398></_FLD3398>
<_FLD3399RREF>00000000-0000-0000-0000-000000000000</_FLD3399RREF>
<_FLD3400></_FLD3400>
<_FLD4424RREF>00000000-0000-0000-0000-000000000000</_FLD4424RREF>
</record>
<record>
<_DOCUMENT122_IDRREF>dc0a6b43-5503-11e8-9479-cdce35f4f3fd</_DOCUMENT122_IDRREF>
<_KEYFIELD>00000001 </_KEYFIELD>
<_LINENO1886>1</_LINENO1886>
<_FLD1887RREF>1ff22c5b-84ee-11e3-933d-0026554acea0</_FLD1887RREF>
<_FLD1888RREF>00000000-0000-0000-0000-000000000000</_FLD1888RREF>
<_FLD4188RREF>00000000-0000-0000-0000-000000000000</_FLD4188RREF>
<_FLD1889>1</_FLD1889>
<_FLD1890RREF>1ff22c5c-84ee-11e3-933d-0026554acea0</_FLD1890RREF>
<_FLD1891>1</_FLD1891>
<_FLD1892>5980</_FLD1892>
<_FLD1893>5980</_FLD1893>
<_FLD1894RREF>8ab98fd8-943a-451a-98e5-973d4b7617e8</_FLD1894RREF>
<_FLD1895>912.2</_FLD1895>
<_FLD1896>0</_FLD1896>
<_FLD1897>0</_FLD1897>
<_FLD1898RREF>00000000-0000-0000-0000-000000000000</_FLD1898RREF>
<_FLD1899_TYPE>01 </_FLD1899_TYPE>
<_FLD1899_N>0</_FLD1899_N>
<_FLD1899_RTREF>00000000 </_FLD1899_RTREF>
<_FLD1899_RRREF>00000000-0000-0000-0000-000000000000</_FLD1899_RRREF>
<_FLD1900>false</_FLD1900>
<_FLD1901>2000001197837</_FLD1901>
<_FLD1902RREF>185600fa-b094-11e1-a511-0026554acea0</_FLD1902RREF>
<_FLD1903>1</_FLD1903>
<_FLD1904RREF>00000000-0000-0000-0000-000000000000</_FLD1904RREF>
<_FLD1905>false</_FLD1905>
<_FLD1906>false</_FLD1906>
<_FLD1907>0-00-00T00:00:00</_FLD1907>
<_FLD2758>false</_FLD2758>
<_FLD2759>0</_FLD2759>
<_FLD2760RREF>00000000-0000-0000-0000-000000000000</_FLD2760RREF>
<_FLD3398></_FLD3398>
<_FLD3399RREF>00000000-0000-0000-0000-000000000000</_FLD3399RREF>
<_FLD3400></_FLD3400>
<_FLD4424RREF>00000000-0000-0000-0000-000000000000</_FLD4424RREF>
</record>
</_DOCUMENT122_VT1885>
<_DOCUMENT122_VT1908>
<record>
<_DOCUMENT122_IDRREF>dc0a6b43-5503-11e8-9479-cdce35f4f3fd</_DOCUMENT122_IDRREF>
<_KEYFIELD>00000001 </_KEYFIELD>
<_LINENO1909>1</_LINENO1909>
<_FLD1910RREF>07b72861-e2a5-49f0-bcca-d7e2e0b0c3d5</_FLD1910RREF>
<_FLD1911>12460</_FLD1911>
<_FLD1912>0</_FLD1912>
<_FLD1913>0</_FLD1913>
</record>
</_DOCUMENT122_VT1908>
<_DOCUMENT122_VT1914></_DOCUMENT122_VT1914>
<_DOCUMENT122_VT1923></_DOCUMENT122_VT1923>
<_DOCUMENT122_VT1926></_DOCUMENT122_VT1926>
<_DOCUMENT122_VT1938></_DOCUMENT122_VT1938>
<_DOCUMENT122_VT1943></_DOCUMENT122_VT1943>
<_DOCUMENT122_VT1947></_DOCUMENT122_VT1947>
<_DOCUMENT122_VT3401></_DOCUMENT122_VT3401>
<_DOCUMENT122_VT3407></_DOCUMENT122_VT3407>
<_DOCUMENT122_VT4081></_DOCUMENT122_VT4081>
</_DOCUMENT122>
Уверен, загрузить такого вида XML не составит большого труда, потому расписывать здесь парсер нет никакого смысла.
Что дальше?
Если у вас есть какие-то интересные случаи, которые можно было бы разобрать — пишите в комментариях, обсудим.
Следующей статьёй я намереваюсь обозреть возможности графической утилитки — бегло рассказать про интерфейс, который отличается от оригинального, и затронуть пару низкоуровневых моментов, которые могут быть полезны в домашнем препарировании файлов баз данных.
Шикарный материал.
На подобном уровне должен бы существовать инструмент по программному созданию объектов метаданных конфигурации + внешних отчетов/обработок.
Например, для сборки файла внешней печатной формы с заполненными по шаблону предопределенными процедурами и приёмами БСП-кидо.
Обработка для программного создания обработок… Программное создание форм по описаниями…. Программное создание регистров по описаниям.
Каждый из 1С-разработчиков быстро нашёл бы способ собрать себе собственную палитру шаблонов кода / описаний МД, чтобы затем на этом уровне программном прослойки делать рутинную работу максимально быстро и максимально привычными способами.
(1)
надеюсь, скоро для этого будет хватать штатных возможностей конфигуратора/EDT. Без участия внешних костылей.
Tool1CD — он всё же про то, когда 1С уже не может.
(2) Любая IDEшка так или иначе навязывает приемы разработки разработчику, иногда полезные, иногда не очень.
Спросите у адептов Eclipse, удобно ли им работать в JetBrains, на совсем чужих «быстрых клавишах», например =)
А ведь у EDT ноги из того же JetBrains’а растут…
Проблема ещё и в проприетарности не только кода платформы, но и форматов файлов конфигурации и внешних обработов/отчеботок.
А за попытки расковырять эти самые форматы ребята в жёлтых майках бьют по пальцам железной линейкой с фирменным логотипом…
(3) Форматы уже давно все расковыряли. Да, есть кое-где белые пятна, но это не мешает. То, что информация не публикуется конкретно на этом портале — это уже вопрос к политике инфостарта.
EDT никак не связано с JetBrains. Оно на eclipse основано.
1С похоже денег пожалели на то, чтобы реальных профессионалов нанять в разработке IDE.
Самому не уверен что пригодится, но!!! За идею и ее реализацию однозначно 5.
«Уверен, загрузить такого вида XML не составит большого труда, потому расписывать здесь парсер нет никакого смысла.»
Не понял. А через ПрочитатьXML он не прочтется ? А почему ?
(6)
потому что сериализатор 1С ничего не знает про эти _FLD12345. Потому всё равно нужен код вида:
СтрокаТаблицы.Номенклатура = Справочники.Номенклатура.ПолучитьСсылку(Новый УникальныйИдентификатор(ХМЛ._FLD12345));
(4) Я давно далек от таких подробностей, хотя и иногда ностальгирую по тем временам.
Егор, Вы взялись бы реализовать задачу, описанную в (1)?
(9) Детишки, ну не занимайтесь ерундой, на карме скажется больше, чем на кошельке отразится =)
(1)
Если я вас правильно понял, то давно уже есть, правда сделано на базе альтернативного распаковщика/запаковщика, см. статьюhttps://infostart.ru/public/454827/
На его базе в том числе сделан онлайн-сервис для генерации шаблонов ВПФ для БСП:
Отличный материал. Но насчет сейчас. Вот какраз-таки сейчас у 1с есть отличная вещь как сервер на несколько рабочих мест. Вполне хватает мне для магазинов, а их у меня больше 50. Везде стоят СКЛ експресы и подобной ситуации по вылету нет. Да и базы намного шустрее!
(12) базы ломаются у разных контор разных размеров и формата деятельности.
PS искренне рад за вас. Я тоже считаю мини-сервер отличным решением для магазинов. Вот только что-то так ни одна сеть у меня и не созрела — дорого, а выхлоп для бизнеса сомнительный.
(12) Сервер это клевая затея, но у нас по формату сети в магазине чаще всего 1 касса, нет компьютера администратора и прочего. есть супервайзеры ответственные за свой сегмент, вот у них мобильный офис на колесах в машине организован. Если касс в магазине => 2 тогда никто не подпишет смету на сервер. поэтому и приходится вертеться)