Видео звонок на базе WebRTC -- meet.gdmn.app. Сделать надежное видео соединение в сетях с низкой пропускной способностью или ограниченных интернет фильтрами -- задача не тривиальная. В статье описываются основные технические проблемы и примененные варианты их решения. Внутри ссылка на репозиторий с полным исходным кодом.
24 апр. 2026 г.
14 авг. 2022 г.
Как приступить к разработке платформы Гедымин
Для разработки платформы необходим компьютер с операционной системой Windows не ниже Windows XP и 8 или 16 Гб ОЗУ. Мы рекомендуем больше памяти при использовании виртуальной машины.
Существует два варианта подготовки инструментария для компиляции. Первый -- установить Delphi 5 и Firebird 2.5 непосредственно на компьютер следуя этой инструкции.
Второй вариант -- это обратиться к специалистам нашей компании за готовой виртуальной машиной с предустановленной системой Delphi и сервером баз данных.
Существует два режима работы Гедымина с сервером базы данных. В режим клиент-сервер необходима клиентская библиотека (fbclient.dll или gds32.dll -- обязательно разрядностью 32 бита!) и запущенный сервер (на этом же компьютере или доступный по сети).
В режиме встроенного сервера необходима библиотека fbembed.dll которая, собственно, представляет собой весь сервер Firebird выполняющийся в адресном пространстве gedemin.exe.
В настоящее время Гедымин поддерживает серверы Firebird 2.5, Firebird 3 и Firebird 4. Для двух последних необходимо дополнительно настроить файл конфигурации firebird.conf.
Некоторые базы данных могут использовать внешние функции из библиотеки GUDF.DLL. Ее следует скачать с нашего сайта и поместить в подкаталог UDF сервера.
Для запуска Гедымина в рабочем режиме потребуется файл базы данных. Это может быть т.н. эталон -- чистая база данных без загруженных прикладных решений. Свежий эталон всегда находится здесь. Либо, можно воспользоваться одной из установок прикладных решений и взять из нее файл базы данных уже с загруженными пространствами имен (так у нас называются файлы с исходным кодом прикладных решений).
Далее, переходим к получению исходного кода, который находится на github.com в приватном репозитории. Обратитесь к сотрудникам компании, чтобы они предоставили вам доступ к нему.
Мы работаем по такому алгоритму:
0. Настраиваем git. Прописываем свое имя пользователя и email командами:
git config --global user.name "FIRST_NAME LAST_NAME"
git config --global user.email "MY_NAME@example.com"
1. Создаем папку \Golden, переходим в нее и клонируем репозиторий себе на компьютер командой:
git clone https://github.com/GoldenSoftwareLtd/gedemin-private.git gedemin
Выполняем действия для подготовки исходников к компиляции, которые указаны в инструкции выше. Компилируем все библиотеки и сам Гедымин согласно инструкции.
2. Основная ветка -- master -- сразу идет в продакшн. В эту ветку мы не комитим изменения напрямую. Перед тем как делать какие-то изменения снимаем код с сервера и создаем новую ветку:
git pull
git checkout -b IssueXXXX
Команду выполняем в папке Gedemin. Имя ветки на ваш выбор.
3. Делаем изменения. Затем комитим их в свою ветку:
Важно! Перед комитом проверяем, что исходники компилируются в Delphi без ошибок.
git commit -a -m "Пишем комментарий"
Перед комитом можно просмотреть сделанные изменения командой:
git status -uno
Важно! Не следует включать в комит следующие файлы, даже если они были изменены:
- gedemin.res, и, вообще, все *.res файлы
- файлы экранных форм *.DFM, где только поменялись координаты экранных элементов при открытии формы в Delphi
Если такие файлы показывает git как измененные, следует вернуть их в исходное состояние. Например, в окне комита оболочки TortoiseGit выбрать такой файл в списке и из контекстного меню вызвать команду Revert.
4. Загружаем изменения в свою ветку в github:
Первый раз следует выполнить команду для загрузки на сервер вашей ветки:
git push --set-upstream origin <YOUR BRANCH NAME>
git push
5. Идем на сайт github.com и создаем Pull Request из вашей ветки в мастер. После того, как ведущий разработчик подтвердит ваши изменения, они попадут в мастер и пойдут в продакшн.
6. На своем компьютере переключаетесь на ветку мастер и снимаете последние изменения:
git checkout master
git pull
7. Подключив телеграм бот @gbuilderbot можно получать уведомления об автоматической компиляции проекта и сборке дистрибутивов.
С чего начать?
Мы планируем доработки и регистрируем ошибки и пожелания в списке Issues в этом репозитории.
Проконсультируйтесь в ведущим разработчиком и выберите себе для начала что-нибудь простое, чтобы познакомиться с организацией исходного кода и внутренней структурой платформы.
Например, доработки вроде этой вообще не требует написания кода, а только правки экранных форм.
По мере ознакомления и вникания в нюансы внутренней организации платформы можно переходить к более сложным заданиям.
22 апр. 2021 г.
Новый сервер компиляции gedemin.exe
Многие годы за автоматическую компиляцию gedemin.exe и формирование пакетов прикладных решений отвечали несколько изощренных bat файлов. Технология пакетной обработки была заложена вместе с первыми версиями DOS еще в начале восьмидесятых прошлого века и предоставляет разработчику очень скудный функционал. Для любого отступления за рамки элементарного копирования/удаления и вызова сторонних программ приходится создавать свои утилиты или приспосабливать свободно доступные из всемирной сети.
Процесс запускался по расписанию один раз в сутки, а не в ответ на изменения в исходном коде платформы и решений.
Все бы ничего, пока строго один gedemin.exe "выпекался" из текущих исходников ветки master в репозитории. Несколько лет назад на крупных предприятиях значение генератора GD_G_UNIQUE стало подбираться к верхнему пределу доступных положительных 32-х битных целочисленных значений. В качестве быстрого решения проблемы мы ввели механизм поиска доступных интервалов в последовательности идентификаторов во всех таблицах базы и записи их в специальную таблицу, откуда Гедымин берет новые идентификаторы по мере необходимости. И... начали думать над долговременным решением, которым должно стать использование 64-х битных целочисленных идентификаторов записей.
Надо сказать, что 20 лет назад никто не задумывался над проблемой исчерпания идентификаторов и внутри исходного кода разработчики сплошь и рядом использовали тип Integer или полагались на длину строго в 4 байта при записи и чтении из буфера. Что еще хуже, Delphi 5 не поддерживает тип Int64 в библиотеке типов COM, через которую объекты Гедымина взаимодействуют с программным кодом на VBScript.
Первым шагом трансформации исходного кода стало введение специального типа для идентификаторов TID и набора функций для преобразования идентификаторов в/из строк, целых чисел, чисел с плавающей точкой и т.п. Разумеется, что замена типа затронула большинство из файлов проекта. Для справки, всего Гедымин насчитывает 5164 .pas файла, если считать вместе со сторонними библиотеками. В зависимости от символа условной компиляции ID64 тип TID превращается либо в 32-х битный Integer, либо в Int64.
Существующий файл базы данных должен пройти через процедуру конвертации, которая меняет домены dintkey, dforeignkey и выполняет последовательность бэкап-рестор. Процесс конвертации базы данных необратим. После перехода на 64 бита вернуться назад уже нельзя.
Таким образом, у нас появляются три версии выполняемого файла:
- стабильный, проверенный временем gedemin.exe c 32-х битными идентификаторами.
- gedemin.exe на основе новых исходников с 32-х битными идентификаторами.
- gedemin.exe c 64-х битными идентификаторами.
Поддерживать такое хозяйство с помощью устаревшей технологии bat файлов и остаться при этом в здравом рассудке не представляется возможным. Пару месяцев назад мы начали проект gbuilder -- сервер компиляции Гедымина и прикладных решений. В настоящее время готова первая очередь. Из специальной ветки с именем india компилируется gedemin.exe на основе стабильных исходников. Прикладные решения формируются из ветки master репозитория gedemin-apps. Сервер компиляции предоставляет разработчику интерфейс через чат-бот в телеграме @gbuilderbot. Компиляция активируется через github webhooks по мере поступления на сервер изменений в исходный код.
В скором времени будет добавлена компиляция бета версий gedemin.exe из новейших исходников с 32-х битными и 64-х битными идентификаторами.
gbuilder реализован на платформе NodeJS. Язык программирования Typescript. Скомпилированные файлы можно скачать из соответствующего раздела нашего сайта.
23 мая 2017 г.
Как не запутаться в зависимостях объектов ПИ
-
Добавить объект в ПИ с зависимыми.
Открыть список ПИ. Найти нужное и по-порядку, по списку входящих в него объектов, проверить что именно добавилось. Убрать лишнее.
Открыть список зависимостей для выбранного ПИ и проверить какие зависимости добавились. При необходимости изменить.
Сохранить ПИ в репозиторий.
Взять чистый эталон и загрузить на него пакет (каждый функционально завершенный и обособленный модуль должен быть оформлен в виде пакета).
Протестировать работоспособность загруженного пакета.
-
В такой базе может присутствовать целый букет устаревших, временных, давно забытых ПИ. При добавлении "с зависимостями" они подхватятся и затянутся в список зависимых ПИ.
В таблицах на таких БД могут присутствовать устаревшие, уже не используемые поля. Мало того, что они затянутся в ПИ, так еще затянутся и объекты на которые они ссылаются.
Устаревшие скрипт-функции могут привести к тому, что код, работающий на разработочной базе, не будет работать на чистой базе, собранной из актуальных ПИ.
-
Поскольку решение не велико, то объекты разобъем по следующим ПИ:
-
GS.Зарплата.Наряды.Метаданные -- домены, таблицы, триггеры и т.п.
GS.Зарплата.Наряды.Хранилище -- экранные формы.
GS.Зарплата.Наряды.Макросы -- перекрытые методы, локальные макросы форм.
GS.Зарплата.Наряды.Отчеты -- печатные формы.
-
GS.Зарплата.Наряды.Метаданные зависит от пакета GS.Зарплата.
GS.Зарплата.Наряды.Хранилище зависит от GS.Зарплата.Наряды.Метаданные.
GS.Зарплата.Наряды.Макросы зависит от GS.Зарплата.Наряды.Хранилище.
GS.Зарплата.Наряды.Отчеты зависит от GS.Зарплата.Наряды.Макросы.
7 июн. 2016 г.
Ветви Cash & Check
git branch
Добавить и переключиться на локальную ветку cash, связать ее с веткой в центральном репозитории:
git checkout -b cash --track origin/cash
Переключиться на ветку master:
git checkout master
Переключиться на ветку cash:
git checkout cash
Получить изменения с сервера в локальную базу данных. Файлы изменены не будут!
git fetch
Применить полученные изменения из удаленной ветки к локальным файлам в текущей ветке:
git merge
Два предыдущих действия одной командой:
git pull
Если ругнется, что локальная ветка не привязана к ветке в удаленном репозитории, то:
git branch --set-upstream-to=origin/cash cash
После чего делаем pull.
Мы в ветке cash. Принимаем изменения из ветки master:
git merge master
ВАЖНО! При возникновении конфликтов принять изменения другой стороны и внести свои коррективы.
Изменили некоторые файлы. Сохраняем изменения в локальном хранилище:
git commit -a -m "some changes were made"
Отправляем изменения в центральный репозиторий:
git push
После того, как изменения в ветке cash протестированы, отправляем их в ветку master:
git checkout master
git merge cash
git commit -a -m "New cash version"
git push
20 нояб. 2013 г.
Формируем ПИ из существующих проектов
-
Проанализируем проект и выделим в нем подсистемы. Пусть, в нашем случае такими будут: Номерной фонд (НФ), Санаторное питание (СП), Медицинские услуги (МУ). Подсистем может и не быть, если проект небольшой и цельный.
Определимся с названиями файлов ПИ. Мы рекомендуем использовать префикс для идентификации разработчика (GS), имя проекта и подсистемы. Например, GS.Санаторий.НФ.Справочник номеров.yml.
Определимся с общими для всех подсистем метаданными (домены, исключения) и разместим их в ПИ GS.Санаторий.Метаданные.yml Аналогично создадим ПИ для общих скрипт-объектов: скрипт-функций, VB-классов, констант.
Для каждого бизнес-объекта или группы строго логически связанных между собой бизнес-объектов создаем отдельное ПИ, куда включаем в такой последовательности: метаданые (по порядку: домены, исключения, таблицы, индексы, представления, процедуры, триггеры), константы, ВБ-классы, скрипт-функции, методы, формы (DFM), события, макросы, отчеты.
Для макросов, форм, отчетов, которые не являются неотъемлемой частью реализации БО, создаем отдельные ПИ. Объекты по ПИ распределяем в соответствии с логической группировкой. Например, в один файл удобно поместить форму, ее события, макрос, который ее вызывает.
Общие отчеты, которые строятся по совокупности данных разных объектов, выносим в отдельное ПИ.
В отдельное ПИ выносим визуальные настройки гридов.
Создаем пакет Санаторий (пакет -- это ПИ со снятым флагом Внутреннее). Расставляем зависимости.
Сохраняем на диске и закидываем в gedemin-apps.
-
Грузим пакет на чистую БД.
С помощью утилиты IBExpert сравниваем структуры старой и новой БД. Выясняем, все ли метаданные мы включили. Если нет, то включаем, сохраняем, возвращаемся к шагу 1.
С помощью утилиты FDBExtract сравниваем данные в таблицах платформы. Выясняем, все ли скрипт-функции, макросы, отчеты, формы мы включили.
Вручную тестируем проект. Если все работает -- идем за пивом и\или шампанским.
1 сент. 2013 г.
Построение списка зависимых объектов
WITH RECURSIVE
ns_tree AS (
SELECT
n.filename AS headname,
0 AS usescount,
CAST((n.xid || '_' || n.dbid) AS VARCHAR(1024)) AS path,
n.filename
FROM
at_namespace_file n
UNION ALL
SELECT
t.headname,
(t.usescount + 1) AS usescount,
(t.path || '-' || n.xid || '_' || n.dbid) AS path,
n.filename
FROM
ns_tree t
JOIN at_namespace_file_link l
ON l.filename = t.filename
JOIN at_namespace_file n
ON l.uses_xid = n.xid and l.uses_dbid = n.dbid
WHERE
POSITION ((n.xid || '_' || n.dbid) IN t.path) = 0
)
SELECT
t.headname, sum(t.usescount)
FROM
ns_tree t
GROUP BY
1
ORDER BY
2
В приведенном запросе at_namespace -- список объектов, а at_namespace_link -- связи между ними. Вычисление пути (path) и дополнительная проверка через функцию POSITION позволяют избежать зацикливания на кольцевых ссылках, если такие попадутся в исходных данных.
8 авг. 2013 г.
Первые шаги в функциональном программировании
my_sum(From, To, C, C2, S) :- From < To, ( From mod C =:= 0; From mod C2 =:= 0 ), Next is From + 1, my_sum(Next, To, C, C2, T), S is T + From. my_sum(From, To, C, C2, S) :- From < To, From mod C =\= 0, From mod C2 =\= 0, Next is From + 1, my_sum(Next, To, C, C2, T), S is T. my_sum(From, To, _, _, S) :- From = To, S is 0.PS: Надо же: Леонард Ойлер оказывается родился в Базеле ))
28 сент. 2012 г.
Compare file version strings
function CompareVersionStrings(const V1,
V2: String): Integer;
function ExtractInt(const V: String;
var B: Integer): Integer;
var
E: Integer;
begin
E := B + 1;
while (B <= Length(V)) and (E <= Length(V))
and (V[E] <> '.') do Inc(E);
Result := StrToIntDef(Copy(V, B, E - B), 0);
B := E + 1;
end;
var
B1, B2: Integer;
begin
B1 := 1; B2 := 1;
repeat
Result := ExtractInt(V1, B1) - ExtractInt(V2, B2);
until (Result <> 0) or
((B1 > Length(V1)) and (B2 > Length(V2)));
end;
1 апр. 2012 г.
Специфика ORM модели платформы Гедымин
-
Не учитывается разница между истинным абстрактным базовым классом (например, TgdcBase), и базовым классом c конкретной ListTable, который служит фундаментом для иерархии наследованных классов (например, TgdcBaseContact).
Некоторые объекты могут использоваться только внутри кода других объектов с выполнением магических действий по программной настройке:
-
Все наследники TgdcInvBaseRemains
TgdcInvCard
TgdcLink
TgdcAcctDocument
TgdcAcctEntryRegister
BN_BANKCATALOGUE, BN_BANKCATALOGUELINE, BN_BANKSTATEMENT, BN_BANKSTATEMENTLINE, BN_CURRCOMMISSION, BN_CHECKLIST, BN_CURRBUYCONTRACT, BN_CURRCOMMISSSELL, BN_CURRCONVCONTRACT, BN_CURRLISTALLOCATION, BN_CURRSELLCONTRACT, BN_DEMANDPAYMENT, CTL_INVOICE, CTL_RECEIPT, GD_TAXDESIGNDATE, GD_TAXRESULT, GD_CONTRACT, GD_DOCREALIZATION, INV_PRICE, INV_PRICELINE, USR$INV_ADDINFO, USR$BN_ACCMAKE, USR$BN_ACCMAKELINE, USR$BN_BILL, USR$BN_BILLLINE, USR$BN_BILLNDS, USR$BN_BILLNDSLINE, USR$BN_BLANKTRIP, USR$BN_BTRIPMONEY, USR$BN_BTRIPMONEYLINE, USR$BN_BUYCURR, USR$BN_CASHBOOK, USR$BN_CASHBOOKLINE, USR$BN_CASHDEPOSIT, USR$BN_CASHDEPOSITLINE, USR$BN_CASHREPORT, USR$BN_CASHREPORTLINE, USR$BN_CHANGECURR, USR$BN_COLLECT, USR$BN_COMMISS, USR$BN_COMMISSLINE, USR$BN_DATABTRIP, USR$BN_DATABTRIPLINE, USR$BN_DEMAND, USR$BN_INCOMECURR, USR$BN_INCOMECURRLINE, USR$BN_LISTDEM, USR$BN_LISTDEMLINE, USR$BN_NOTICE, USR$BN_NOTICELINE, USR$BN_ORDERBTRIP, USR$BN_ORDERBTRIPLINE, USR$BN_PAYMENT, USR$BN_SALECURR, USR$BN_SALECURRLINE, USR$BN_SHARECURR, USR$BN_SHARECURRLINE, USR$BN_TRANSFER, USR$BN_TTN, USR$BN_TTNLINE, USR$BNF_ACTS, USR$BNF_ACTSLINE, USR$BNF_CONTRACT, USR$BNF_CONTRACTLINE, USR$CHECKREGISTER, USR$CHECKREGISTERLINE, USR$CURR_PAYMENT, USR$FA_ACTNEW, USR$FA_ACTNEWLINE, USR$FA_AMORT, USR$FA_AMORTLINE, USR$FA_CHANGEPROP, USR$FA_CHANGEPROPLINE, USR$FA_COMPLECT, USR$FA_COMPLECTLINE, USR$FA_CONSERVATIONLINE, USR$FA_CONSERVATION, USR$FA_MOVEMENT, USR$FA_MOVEMENTLINE, USR$FA_REAPP_B, USR$FA_REAPP_BLINE, USR$FA_REAPP, USR$FA_REAPPLINE, USR$FA_REMONT, USR$FA_REMONTLINE, USR$FA_REPAIR, USR$FA_REPAIRLINE, USR$GS_ACCBALANCE, USR$GS_ACTWORK, USR$GS_ACTWORKLINE, USR$INCOME_ORD, USR$INCOME_ORDLINE, USR$INV_ACTWORK, USR$INV_ACTWORKLINE, USR$INV_ADDWBILL, USR$INV_ADDWBILLLINE, USR$INV_ATTORNEY, USR$INV_ATTORNEYLINE, USR$INV_BILL, USR$INV_BILLLINE, USR$INV_CARDPRMET, USR$INV_CARDPRMETLINE, USR$INV_CERT, USR$INV_CHANGEPERC, USR$INV_CHANGEPERCLINE, USR$INV_COMP, USR$INV_COMPLINE, USR$INV_CONTRACT, USR$INV_CONTRACTLINE, USR$INV_DECOMP, USR$INV_DECOMPLINE, USR$INV_GOODORDER, USR$INV_GOODORDERLINE, USR$INV_INVENT, USR$INV_INVENTLINE, USR$INV_INVMOVE, USR$INV_INVMOVELINE, USR$INV_NEWCOST, USR$INV_NEWCOSTLINE, USR$INV_OUTLAYS, USR$INV_PROCESSING, USR$INV_PROCESSINGLINE, USR$INV_PRODUCT, USR$INV_PRODUCTLINE, USR$INV_PRREC, USR$INV_PRRECLINE, USR$INV_REALCOMMIS, USR$INV_REALCOMMISLINE, USR$INV_RETAIL, USR$INV_RETAILLINE, USR$INV_RETCUST, USR$INV_RETCUSTLINE, USR$INV_RETPROV, USR$INV_RETPROVLINE, USR$INV_SELLBILL, USR$INV_SELLBILLLINE, USR$INV_SPEND, USR$INV_SPENDLINE, USR$INV_SPENDPREC, USR$INV_SPENDPRECLINE, USR$INV_TOTRADE, USR$INV_TOTRADELINE, USR$MOG_DEBTACC, USR$MOG_DEBTCONTR, USR$MOG_INBILLVAT, USR$MOG_INBILLVATLINE, USR$MOG_SERVICE, USR$REN_DIVSTATEMNLINE, USR$SKIDKI, USR$SKIDKILINE, USR$WG_ADDPAYBYPERIODLINE, USR$WG_ADDPAYBYPERIOD, USR$WG_AGREEMENTLONGLINE, USR$WG_AGREEMENT, USR$WG_AGREEMENTLINE, USR$WG_AGREEMENTLONG, USR$WG_ALIMONY, USR$WG_ALIMONYDEBT, USR$WG_ATTEST, USR$WG_AVGADDPAY, USR$WG_AVGADDPAYLINE, USR$WG_BANKCALC, USR$WG_BRIGADEORDERLINE, USR$WG_BRIGADEORDER, USR$WG_CHARGEREG, USR$WG_CHILDAID, USR$WG_CONTRACT, USR$WG_CONTRACTLINE, USR$WG_CORRECT, USR$WG_CORRECTLINE, USR$WG_FAMCHAG, USR$WG_HAZARDS, USR$WG_HAZARDSLINE, USR$WG_HOLIDAYWORK, USR$WG_HOLIDAYWORKLINE, USR$WG_INCTAXDEDUCTION, USR$WG_INCTAXOTHERPAYLINE, USR$WG_INCTAXOTHER, USR$WG_INCTAXOTHERPAY, USR$WG_INCTAXSECURITIES, USR$WG_INITINCOME, USR$WG_INITINCOMELINE, USR$WG_KINDDAY, USR$WG_KINDDAYLINE, USR$WG_LEAVEDOC, USR$WG_LEAVEDOCLINE, USR$WG_LEAVEPASS, USR$WG_LEAVESCHED, USR$WG_LEAVESCHEDLINE, USR$WG_LEAVESTOPDOC, USR$WG_MANUALINPUT, USR$WG_MANUALINPUTLINE, USR$WG_MOVEMENT, USR$WG_MOVEMENTLINE, USR$WG_MULTIORDER, USR$WG_MULTIORDERLINE, USR$WG_PARTDAY, USR$WG_PARTDAYLINE, USR$WG_PENALTYDOC, USR$WG_PERSONALORDERLINE, USR$WG_PERSONALORDER, USR$WG_PIECEWORK, USR$WG_PIECEWORKLINE, USR$WG_PROFDEVELOP, USR$WG_PU6, USR$WG_PU6LINE, USR$WG_RETRAINING, USR$WG_REWARDDOC, USR$WG_SALARYCALC, USR$WG_SALARYCALCLINE, USR$WG_SALARYPAY, USR$WG_SALARYPAYLINE, USR$WG_SCIENCEDEVELOP, USR$WG_SENCALC, USR$WG_SENCALCLINE, USR$WG_SETPAYMENT, USR$WG_SETPAYMENTLINE, USR$WG_SETSENBONUS, USR$WG_SICKLIST, USR$WG_SICKLISTJOURNAL, USR$WG_SICKLISTLINE, USR$WG_SINKDEBT, USR$WG_SINKDEBTLINE, USR$WG_STAFFLIST, USR$WG_STAFFLISTLINE, USR$WG_TAXATION, USR$WG_TBLCAL, USR$WG_TBLCALLINE, USR$WG_TIMEWORK, USR$WG_TIMEWORKLINE, USR$WG_TOTAL, USR$WG_TOTALLINE, USR$WG_VACATION, USR$WG_VACATIONLINE, USR$WG_WRITEOFF, USR$WG_WRITEOFFLINE, USR$WS_DISTANCE_LINE, USR$WS_FUEL_LINE, USR$WS_WAYSHEETКак уже отмечалось выше, связь мастер-дитэйл обрабатывается платформой только для документов и только на уровне пользовательского интерфейса. Связь мастер-дитэйл-сабдитэйл не обрабатывается вообще никак. Наследование подтипов невозможно. Не лишней была бы возможность создать атрибут типа бизнес-класс. То, что сейчас решается созданием автономного объекта и ручным связыванием его с головной записью. Пример: дополнительная информация по товарно-транспортной накладной.
7 дек. 2011 г.
etalon.sql
... FC first.txt second.txt /C | FIND "FC: no dif" > nul IF ERRORLEVEL 1 goto s_files_are_different ... :s_files_are_different ...
28 нояб. 2011 г.
Брюки превращаются, превращаются брюки...
25 мар. 2010 г.
Ветка gedemin-2.5 в SubVersion
Сделайте switch или свежий check out. В последнем случае, не забудьте сохранить незакомиченные изменения.