вторник, 31 июля 2007 г.

Система: MorphX, среда разработки

[id:034]

Полное имя — MorphX Development Suite.
Так называется среда разработки в Axapta, или по ненашему — Integrated Development Environment (IDE).

Все, что связано с проектированием форм и отчетов, редактированием компилированием и отладкой кода, все это — MorphX.

Выбери класс AddressSelectForm_PurchLine IDE интегрирована с самой системой. Что представляет из себя редактор X++ кода? Откройте AOT и два раза щелкните на имени класса "AddressSelectForm_PurchLine".

Увидите окно редактора X++: Окно редактора кода Вот он какой северный олень. В панели слева отображается список всех методов класса «AddressSelectForm_PurchLine»; содержимое выделенного метода показывается справа. У любого класса присутствует строка "classDeclaration" в левой панели. Это не метод; в нем выводится объявление класса (как называется класс, от кого наследуется) и объявление его полей. Переходить по отображенным методам редактора можно с помощью комбинации Ctrl+Tab и Ctrl+Shift+Tab.

По началу такое представление было очень непривычным. Привык видеть все методы внутри класса, как в .NET. Но куда денешься?! Замечу на будущее: я буду приводить примеры кода классов в манере .NET, не вынося тело каждого метода за границы класса.

Итог

  • нужно привыкнуть к редактору кода
  • Ctrl+Tab — для перехода по методам на левой панели редактора.

четверг, 26 июля 2007 г.

Пожиратель огурцов

Рабочие места на моей работе сделаны на американский манер — перегородки, отделяющие столы, и это все — в большой комнате.

За перегородкой сидит парень деревенской наружности, 185 сантиметров по вертикали и... ЖРЕТ ОГУРЦЫ в течение последних СТА МИНУТ!!! Хруст начал добивать. Под конец огуречного марафона возникло стойкое ощущение, что я объелся огурцов, во рту появился специфический привкус огурцовой кожуры, темно-зеленой такой.

1 кг огурцов дают организму 150 килокалорий. За два часа можно перемолоть не менее килограмма. Таким образом, ртом он добыл 150 килокалорий и набил свой желудок.
Коню-соседу нужно около 3000 килокалорий в день, чтобы жить. Если грубо поделить эти три тысячи на 24 часа, что есть в нашем распоряжении каждый день, получается - 125 килокалорий в час необходимо засовывать в организм. За два часа - 250 килокалорий, которые нужно как-то восполнить.
Потери энергии: 250 (килокалорий, которые нужны нашему коню за прошелшие два часа) - 150 (килокалорий, что он выжал из огурцов за теже два часа) = 100 килокалорий

Хочет похудеть!
Бегай, жиробас!
Ах, бег тебе противопоказан?
И ты бегал раньше, но не помогло?

Я бегал по утрам - ни одного жирного не видел, все вокруг были поджарые. Какие еще отговорки будут?

среда, 25 июля 2007 г.

X++: наследование 1

[id:029]

Наследовать класс можно только от одного класса.

Создаем класс BLG29_ClassBase с конструктором: class BLG29_ClassBase { int iMyVar; void new() { iMyVar = 123; print 'constructor of base class'; } }

Создаем дочерний класс BLG29_ClassChild, туда же помести метод main(). Внимание на слово "extends": class BLG29_ClassChild extends BLG29_ClassBase { // конструктор класса void new() { super(); print 'constructor of inherited class'; } int getMyVar() { return iMyVar; } static void main(Args _args) { BLG29_ClassChild cls; cls = new BLG29_ClassChild(); print cls.getMyVar(); pause; } }

У меня появилось: Результат. Родительский класс тоже отработал

Слово "super" в конструкторе класса BLG29_ClassChild вызывает конструктор родительского класса BLG29_ClassBase.
Конструктор класса BLG29_ClassBase не запускается автоматически, попробуй закомментировать строку с вызовом super() в конструкторе класса BLG29_ClassChild.
Получишь: Результат отключения вызова родительского конструктора

Итог
  • наследование задается с помощью слова «extends»;
  • наследовать можно только от одного класса;
  • модификаторы доступа (public, protected, private) при наследовании не задаются (как в .NET);
  • доступ к перегруженным методам базового класса из дочернего — через волшебное слово "super";

X++: абстрактный класс

[id:032]

Создаем абстрактный класс и метод в нем (внимание на ключевое слово "abstract"): abstract class BLG32_AbstractClass { int iMyVar; int MyMethod() { return iMyVar + 100; } }

Еще класс с методом main(): class BLG32_Class { static void main(Args _args) { BLG32_AbstractClass cls; cls = new BLG32_AbstractClass(); } }

Что получил? Ошибка компиляции. На то он и абстрактный, что нельзя создать объект этого класса.
Исправляем ошибку. Для этого сделаем класс BLG32_Class наследником от BLG32_AbstractClass и будет обращаться к реальному классу, а не какой-то там абстракции: class BLG32_Class extends BLG32_AbstractClass { static void main(Args _args) { BLG32_AbstractClass cls; cls = new BLG32_Class(); print cls.MyMethod(); pause; } }

Я увидел цифру 100. А ведь мы даже не переопределяли метод MyMethod() в классе BLG32_Class! А все потому, что MyMethod() вполне реальный метод, несмотря на то, что класс, где он размещен, абстрактный.
Экспериментируем дальше, сделай метод MyMethod() абстрактным: abstract class BLG32_AbstractClass { int iMyVar; abstract int MyMethod() { // Абстрактный метод должен быть пустым, иначе - заругають! //return iMyVar + 100; } }

Заметь, я отчистил тело метода.
А в классе BLG32_Class я переопределил метод: class BLG32_Class extends BLG32_AbstractClass { int MyMethod() { return iMyVar + 1000; } static void main(Args _args) { BLG32_AbstractClass cls; cls = new BLG32_Class(); print cls.MyMethod(); pause; } }

Результат: цифра 1000.

Итак:

  • в неабстрактный метод абстрактного класса можно что-нибудь написать
  • тело абстрактного метода должно быть пустым (как у интерфейса)
  • в отличие от наследования интерфейса, при наследовании от абстрактного класса начинает работать полезный пункт «Перекрыть метод». Попробуй:
    Переименуй метод MyMethod() во что-нибудь другое. Щелкни правой клавишей в окне проекта на классе BLG32_Class, пункт «Перекрыть метод» и тебе откроется список методов, доступных для перегрузки. Не правда ли, это хорошая возможность поберечь свои пальцы?

X++: объявление интерфейса

[id:027]

Интерфейс создается как и класс, в той же ветке — "Classes"; отличие в ключевом слове "interface".

Пишем. Создаем интерфейс "BLG27_MyInterface" и метод в нем: interface BLG27_MyInterface { void methodToImplement() { } }

Создайте класс "BLG27_Class" (внимание на слово "implements") и метод main() в нем: class BLG27_Class implements BLG27_MyInterface { static void main(Args _args) { BLG27_Class cls = new BLG27_Class(); cls.methodToImplement(); pause; } }

Компилируем и получаем ошибку «забыл реализовать метод methodToImplement()». Исправляем этот недочет, создайте метод на классе BLG27_Class: void methodToImplement() { print 'methodToImplement'; }

Запускайте. Увидите строку «methodToImplement».
Сохрани "BLG27_MyInterface", он еще понадобится.

Итог:

два ключевых слова для работы с интерфейсами — interface и implements.

X++: метод main()

[id:025]

Метод main() — это точка входа для класса. Если знаком с методом main() из мира C#, то здесь все точно также. Хотя он создается в рамках конкретного класса, метод нужно рассматривать, как нечто обособленное.

Выглядит следующим образом: static void main(Args _args) { // Здесь ваш код }
main() — статический метод. Обязательно присутствует параметр типа Args, в нем передаются возможные параметры. Параметры именно возможные, но не обязательные.

Попрактикуемся. Создайте класс: public class BLG25_Class { }

Чтобы запустить класс, нужно его открыть: щелкните правой кнопкой на классе в дереве проекта, пункт «Открыть». И ничего не произойдет Открываем класс

Создайте метод main() в классе BLG25_Class: public class BLG25_Class { static void main(Args _args) { ; info('Hello, world!'); } }
Теперь снова откройте класс. Появиться сообщение, замозолившее программисту глаза.

Итог

main — статический метод, играет роль точки входа на классе. Нужен, прежде всего, для целей тестирования.

X++: поля класса

[id:24]

Здесь и далее использую термин «поле класса» в том же значении, как это было в С++: это переменные, объявленные в классе (но не в его методах).

Пробуем создать поле.
Создаем класс BLG24_ClassBase и в нем объявляем поле iMyVar типа int и конструктор инициализации поля: class BLG24_ClassBase { int iMyVar; void new() { iMyVar = 123; } }

Создаем еще один класс "BLG24_ClassChild" и в нем определяем статический метод main(): class BLG24_ClassChild { static void main(Args _args) { BLG24_ClassBase cls; cls = new BLG24_ClassBase(); print cls.iMyVar; pause; } }

Компилируйте. Не получилось? Значит делаем вывод: доступ к полям класса BLG24_ClassBase «из вне» не возможен. Возьмите на заметку.

Делаем класс BLG24_ClassChild дочерним от BLG24_ClassBase с помощью ключевого слова "extends". Добавляем метод getMyVar(), чтобы получить значение поля и переписываем имеющийся метод main(): class BLG24_ClassChild extends BLG24_ClassBase { int getMyVar() { return iMyVar; } static void main(Args _args) { BLG24_ClassChild cls; cls = new BLG24_ClassChild(); print cls.getMyVar(); pause; } }

Запустите метод main(). Результат: Результат - получили значение поля базового класса

О наследовании классов расскажу позже.

Итог

поля класса видят только методы данного класса и его дочки. Всем остальным доступ закрыт

вторник, 24 июля 2007 г.

X++: объявление строковой переменной

[id:023]

Чтобы объявить строковую переменную используется зарезервированное слово "str". По-умолчанию у строки неограниченная длина (сам я не проверял это утверждение). Но можно задать максимальную длину.

Пробуем. Создайте джоб: static void BLG23_Job(Args _args) { str strValue1 = "string"; str 3 strValue2 = "string"; print strValue1 + ' ' + strValue2; pause; }
Первая переменная "strValue1" является безразмерной строкой. Вторая "strValue2" может вместить максимум три символа. В результате мне показали строчку «string str».

Наблюдательный человек заметил, что строки я заключил сначала в двойные (при объявлении переменных), а потом — в одинарные кавычки (чтобы вставить пробел при конкатенации строк). А компилятор не ругается.
В Аксапте приемлемы оба типа. Давайте использовать одинарные кавычки; а двойные оставим для другого случая.

Итог:
  • строковая переменная создается с помощью ключевого слова "str";
  • можно указать максимальный размер строковой переменной;
  • строковые константы заключайте в одинарные кавычки.

Общее: создание проекта 2

[id:022]

Обобщая сказаное, проект — инструмент группировки объектов (форм, отчетов, запросов, таблиц и т.п.), инструмент повышения удобства разработки в системе. Где бы ты и что бы ты не создал, все эти объекты появятся в АОТ. В проекте ты видишь только ссылки на объекты. Верно и другое: если перетаскиваешь какой-либо объект из AOT в проект, то это вовсе не «перемещение», а создание ссылки на объект в проекте. Пробуем.

Создай новую форму в текущем проекте (щелкай правой кнопкой на проекте, пункт «Создать», строка «Form»). Появилась новая форма «Form1».

Создаем форму

И красной вертикальной полосой
Будут помечены объекты,
Что изменил, но не запомнил ты.
JayS, сборник «Криворукие стихи, замаскированные под хайку»

Созданая форма Нажми «Сохранить все» (на предыдущем рисунке отмечено красным овалом), либо Ctrl+Shift+S. Теперь открой AOT, и увидишь созданную форму.

Двойное удаление Вернись к окну проекта, на форме «Form1» щелкни правой клавишей и в контекстном меню заметишь две строки-близняшки:

Как прикажете исчезнуть, сэр? Что конкретно делает каждая из них можно понять только из текста в строке состояния, когда наводишь указатель мыши. Одна — это команда «Исключить выбранный объект из проекта» — т.е. из проекта удаляется ссылка на выбранный объект, но он остается жить в AOT. Другая — открывает диалог, где выбираешь: исключить из состава коммунистической партии Советского Союза, либо расстрелять, как троцкиста и выродка белогвардейской контры:

Удали полностью, из системы эту форму.

Может статься так, что ты создал объект, сохранил его, даже набросал парочку методов и скомпилировал. Но вдруг «Service has been terminated» и Axapta самостоятельно закрылась. Ты снова запускаешь ее, открываешь проект и не наблюдаешь свои объекты. Торопиться не нужно. Прежде всего посмотри в AOT.

Система: авторизация пользователей

[id:021]

Система Axapta 4.0 не спрашивает имя пользователя и пароль при запуске: все данные берутся из домена Active Directory. То есть, поддерживаться только режим Windows-аутентификации.

В версии 3 Axapta позволяла вводить имя пользователя и пароль, не запрашивая информации у домена.

Для любопытных товарищей: параметры всех пользователей хранятся в таблице UserInfo на сервере базы данных. Поля, которые могут представлять интерес: ID, SID, NETWORKDOMAIN, NETWORKALIAS.

SID — security identificator, или идентификатор доступа. Чтобы узнать SID пользователя вам поможет программа "SID&User".

С кого спрашивать

Если у тебя возникли вопросы при чтении моих уроков по Axapta, пиши — jay_temp@pochta.ru

Признаю за собой неприязнь к вэб-чатам, форумам и тому подобному. Комментарии в блоге очень напоминают эти самые форумы.
Возник вопрос — подумай, сформулируй его, и напиши мне письмо. Я отвечу. Мало того, если по твоим письмам станет очевидно, что какой-то урок слишком непонятен — он будет переписан.
Если автор письма в заголовке пишет: «Срочно нужна помощь!!!» или «Не могу понять» или «И снова этот DataSource…», — это очевидный сигнал, что человек не сильно напрягал свое серое вещество при написании. Он просто почувствовал внутреннюю потребность задать вопрос, а что ему конкретно непонятно — пусть это выяснится в процессе переписки с адресатом. Так дело не пойдет

понедельник, 23 июля 2007 г.

Axapta 4.0, по шагам

Изучение Microsoft Dynamics AX 4 с самого начала

Статьи ориентированы на программистов C# и С++ прежде всего.
Я предполагаю, что вы знаете базовые конструкции этих языков (for, while, switch, try, catch и так далее). Вы уже создавали SQL-запросы, знаете типы соединений наборов записей.

Статьи добавляются в любом месте списка, приведенного ниже, в соответствии с моим понимаем, что нужно изучить сначала, а что - потом.

  1. Microsoft Dynamics AX
  2. AOT - Application Object Tree
  3. Система: архитектура 1
  4. Система: архитектура 2
  5. Система: слои 1
  6. Система: слои 2
  7. Система: слои 3
  8. Общее: создание проекта 1
  9. Общее: создание проекта 2
  10. Общее: создание группы элементов
  11. X++: самый первый джоб
  12. X++: case insensitive, скажи нет IntelliSense-у
  13. Система: MorphX, среда разработки
  14. X++: базисные типы данных
  15. X++: объявление строковой переменной
  16. X++: точка с запятой
  17. X++: метод strfmt()
  18. Система: InfoLog, часть 1
  19. Система: InfoLog, часть 2. Иерархия c помощью setprefix()
  20. Система: таблица, табличная переменная
  21. X++: SELECT 1
  22. Данные: перебор с помощью while select
  23. X++: метод main()
  24. X++: наследование 1
  25. Система: компиляция
  26. X++: поля класса
  27. Форма: this is my first time, часть 1
  28. Форма: this is my first time, часть 2
  29. Форма: this is my first time, часть 3
  30. Форма: создание столбцов на гриде
  31. X++: аксессоры 1
  32. X++: аксессоры 2
  33. X++: объявление интерфейса
  34. X++: абстрактный класс
  35. Терминология: номенклатура, ассортимент
  36. Система: макросы 1
  37. Система: макросы 2
  38. Система: макросы 3
  39. Терминология: компания
  40. X++: логическое И
  41. X++: исключения, часть 1
  42. X++: исключения, часть 2
  43. Система: авторизация пользователей
  44. X++: открыть документ Word
  45. Система: выполнение команд при запуске 1
  46. Система: выполнение команд при запуске 2
  47. Система: выполнение команд при запуске 3
  48. Система: как бы закрыть окно
  49. Форма: запуск с параметрами

Система: слои 3

[id:020]

Слой "USR" доступен для создания своего кода, родненького, сразу и навсегда… естественно, если куплена лицензия на разработку в Axapta.

Во время соотворения Аксапты было задумано, что компания-внедренец системы будет писать свои модификации "CUS" и "VAR" слои. Но на практике, чтобы перейти на другой, кроме "USR", слой, нужно иметь лицензионный ключ.

Платить за лицензии люди не любят. Поэтому внедренцы пишут модификации для конкретных клиентов в слой "USR". И, когда накапливаются наработки в конкретной отрасли, внедренец становится достаточно самоуверен и амбициозен, покупается лицензия и готовое решение опускается в слой "VAR" или "BUS" (насколько наглости хватит). Далее все как обычно: пресс-релиз, удары в грудь, красочные маркетинговые материалы про наше уникальное решение, которое без базара и без аналогов войдет в анналы.

Чтобы изменить текущий слой, зайдите в утилиту конфигурации клиента (описано в другом уроке) и на вкладке "Developer" выберите нужный слой. НО: для любого слоя, кроме USR/USP тебе придется ввести лицензионный код. А слой "SYS" вообще привилегия Майкрософт. Настройка текущего слоя

Система: слои 2

[id:019]

Итак, объекты, определенные на более высоких слоях, перекрывают объекты, определенные на более низких слоях.
Пример.

Пусть имеются четыре объекта: форма «А», запрос «Б», класс «С» и таблица «Д». На приведенном рисунке черными кружками отмечены уровни, на которых определен объект. Например, форма «А» присутствует в слое USR и SYS.

Что делает система. Она скачет по верхам: при обращении к форме «А» будет использоваться форма «А» слоя USR, для запроса «Б» — из слоя GLS, для класса «С» — из слоя «LOS», и для таблицы «Д» — из слоя «USR». Можем предположить, что в данном случае у клиента установлено некоторое вертикальное решение (например, для розничной торговли) в слое BUS и выполнены некоторые модификации по пожеланию пользователей в слое USR.

Теперь предложим, что бизнес-партнер Майкрософт, как автор решения для розницы, нашел кучу ошибок в своем детище или в очередной раз изменились правила ведения торговли. В результате — новая версия в BUS-слое:

В новой версии оказались измененными объекты — запрос Б и таблица Д. Вы, как ответственный за обновление версии, посмотрите (позже объясню, как это сделать) и определите, что уникальная модификация для нашего клиента «вступила в конфликт» с новой версией. Точкой вмешательства является таблица Д, потому что она была переопределена в вышележащем USR-слое. Там будет смотреть программист и модифицировать таблицу в слое USR, чтобы все сочеталось с новой версией розничного решения.
Еще раз: модификация под конкретного клиента была положена в USR-слой, следовательно, когда «подложили» новый слой BUS нужно проверить пересечения объектов из USR и BUS слоев.
Конфликты объектов BUS-слоя с ниже лежащими слоями мне фиолетово безразличны — это проблемы автора розничного решения.

Таким образом, слои реализуют концепцию "Это не мое дело", то есть - служат идеи распределения ответственности между разработчиками и для удобного управления модификациями.
Степень удобства слоености системы Axapta, вы по-настоящему поймете, когда изучите механизмы экспорта/импорта, ну и когда Axapta станет для вас инструментом пропитания.

Продолжение следует...

Система: слои 1

[id:008]

Слои в Axapta Герой мультфильма людоед Шрек  состоит из слоев, как лук или торт. Система Axapta тоже слоенная.

Системный слой самый нижний, слой пользовательский — самый верхний. Axapta просматривает слои сверху-вниз в поисках нужных объектов (форм, классов, отчетов …). Как только найдет нужный объект — дальше не копает.
Маленькие слои-прокладочки на рисунке, оканчивающиеся на «..P», служат целям латания дыр: в них нужно помещать патчи (pathes) и хотфиксы (hotfixes). Этими прокладками пользуются редко, но не потому что Axapta такой безошибочный продукт.

Объекты, определенные на более высоких слоях, перекрывают объекты, определенные на более низких слоях.

Продолжение следует ...

пятница, 20 июля 2007 г.

Система: макросы 3

Проект для урока [id:016]

Есть еще одна штука — макробиблиотека, macro library. Создается она и внешне выглядит как автономный макрос, но только внутри себя содержит несколько локальных макросов. Поясню.

Как обычно создай проект "Blog16" с двумя ветками для джобов и для макросов. Создай макробиблиотеку "BLG16_MacroLib" и там напиши: #define.ITEM_ID('Батарейка-R6') #globalmacro.SelectMyInventItem select * from %1 #IFNOT.EMPTY(%2) where %1.ItemId == %2 #ENDIF ; print %1.ItemName; #endmacro

Создай джоб "BLG16_Job", а в нем: static void BLG16_Job(Args _args) { InventTable inventTable; #SelectMyInventItem(inventTable, #ITEM_ID) #SelectMyInventItem(inventTable) pause; }

Запускай! Хе-хе, кури бамбук, товарищ. Ошибка компиляции "Макрос не существует". Пока чуть-чуть объясню, что вообще мы сделали.

Создать макробиблиотеку - все равно, что создать автономный макрос. Но: для последнего имя элемента являлось бы именем самого макроса. А для макробиблиотеки имя элемента = имя библиотеки (у нас, получается, библиотека называется «BLG16_MacroLib»). Библиотеку можно напичкать автономными макросами и макроконстантами. Я скромненько запихнул лишь одну константу с красивым узбекским именем «ITEM_ID» и один макрос «SelectMyInventItem». Как объявить макроконстанту уже знаешь. Объявление макроса же начинается с фразы «#localmacro» и длиться пока «#endmacro» не разлучит нас.

Разбираем макрос «SelectMyInventItem». В нем ожидается два параметра: %1 — имя табличной переменной, для которой будет выполняться выборка данных; %2 — необязательный идентификатор номенклатуры, которую нужно найти. Фраза «#IFNOT. EMPTY(%2)» говорит: если второй параметр был задан (он не пуст), то вставь здесь текст до «#ENDIF», т. е. строчку «where %1.ItemId == %2». И что получается: если я задаю второй параметр, то в запрос SELECT будет вставлено условие выборки по идентификатору номенклатуры (по полю ItemId). Иначе — ничего.

При компиляции строка "#SelectMyInventItem(inventTable, #ITEM_ID)" смениться на: select * from inventTable where inventTable.ItemId == 'Батарейка-R6' ; print inventTable.ItemName;

А строка "#SelectMyInventItem(inventTable)" станет: select * from inventTable ; print inventTable.ItemName;

Вернемся к ошибке. Если автономный макрос доступен сразу, то макробиблиотеку нужно подключить перед использованием. Это напоминает директиву "#include" в С++ или "using" из мира C#. Только здесь для подключения нужно поставить символ решетки и имя библиотеки. С учетом этого текст джоба должен выглядеть так: static void BLG16_Job(Args _args) { #BLG16_MacroLib InventTable inventTable; #SelectMyInventItem(inventTable, #ITEM_ID) #SelectMyInventItem(inventTable) pause; }

Результат для моей базы:

четверг, 19 июля 2007 г.

Терминология: номенклатура, ассортимент

[id:015]

Номенклатура — все товары и услуги, с которыми когда-либо работала компания. К основным характеристикам номенклатур относятся: номенклатурный номер, наименование, единица измерения.

Ассортимент товаров — набор товаров, объединенных по какому-либо одному или совокупности признаков.

В общем, номенклатура — это все товары и услуги, с которыми имели дело (услуга «Молдоване клеят кафельную плитку», товар «Печеньки, такие вкусненькие, маленькие»), а ассортимент — группа номенклатур, похожих по каким-то признакам (например, ассортимент зимних мужских ботинок включает: белые/красные/черные/коричневые зимние мужские ботинки).

Таблицы Аксапты, которые связаны с номенклатурой, начинаются на «Invent». Например, собственно перечень всех номенклатур — это таблица InventTable.

X++: case insensitive, скажи нет IntelliSense-у

[id:014]

Плохие новости:
Язык X++ "бесчувственен" к регистру идентификаторов (имен переменных, методов, классов и т.п.). Добро пожаловать обратно в хаос Visual Basic (правды ради нужно сказать, что среда разработки последнего следит за порядком).

Если ты когда-нибудь соприкоснулся со штукой под названием IntelliSense в VisualStudio 2005, то мужайся: в Аксапте версии 4.0 этого нет. Точнее есть, но на уровне Borland C++ 5.0 девяносто какого‑то года.

Спасибо, больше бумажных пакетиков не нужно. Уже не тошнит на клавиатуру. Программирую нормально.

Система: таблица, табличная переменная

[id:013]

Таблица в Аксапте — это класс-надстройка над физической таблицей в базе данных. Ты работаешь с этим классом как с таблицей базы данных, только программно. Плюс к этому на таблице в Аксапте можно создавать свои методы.
Объяснение для .NET-программистов: таблица в Аксапте похожа на Strongly-typed DataSet, который создается в DataSet Designer в VisualStudio (начиная с версии 2003).

Табличная переменная — это как экземпляр класса-таблицы. Но он ведет себя как курсор, то есть указывает на текущую запись в наборе данных.
Работа с данными (создание, изменение, удаление) в большинстве случае выполняются с помощью табличных переменных.

Вот смотрите: EmplTable emplTable; так я объявил табличную переменную "emplTable" для таблицы "EmplTable" (там хранится список сотрудников компании). Пока мы не стоим ни на какой записи и моя табличная переменная "emplTable" указывает в никуда. Но стоит сделать так: select from emplTable where emplTable.EmplId == 'AFE'; и вот мы уже наша "emplTable" ссылается на запись о сотруднике с кодом "AFE". И, написав после этого код: print emplTable.Name; я увидел имя сотрудника - "Грачев Николай".

Пока не загружайтесь тем форматом SQL-запросов, что принят в Аксапте и прочими мелочами. Главное, чтобы стали понятны термины «таблица» и «табличная переменная».

И еще. Раз уж таблица в Аксапте — это класс —, то логично предположить, что все они (таблицы) имеют общего родителя. Этот общий родитель — класс Common. Соответственно, любую табличную переменную можно присвоить переменной класса Common.

Итог:
  • таблица в Аксапте является гибридом таблицы базы данных и класса;
  • работать с таблицами нужно через табличные переменные;
  • класс Common является прадедушкой всех таблиц.

Система: макросы 2

[id:003]

Проект для урока Создай новый проект «Blog3» с двумя группами в нем: «Macros» и «Jobs». В них создай макрос "BLG3_SelectInventTable" и джоб "BLG3_Job" в соответствующих папках. Мы будем выводить несколько полей (идентификатор группы и идентификатор единицы) для первой попавшейся записи из таблицы InventTable. В ней находиться список номенклатур, с которыми работает наша компания (с теми, что она продает, покупает, владеет). Итак, введи следующий текст.

Текст для макроса: select %2 from %1; print %1.%2;

Текст для джоба: static void BLG3_Job(Args _args) {   InventTable inventTable1;   #BLG3_SelectInventTable(inventTable1, ItemGroupId)   #BLG3_SelectInventTable(inventTable1, ItemId)   pause; }

У меня выдало следующее: PBA Ак-бат1

Проанализируем, что сделали. Когда добавили элемент "BLG3_SelectInventTable" в ветке Macros, получилось, что мы создали обособленный макрос с этим именем. Позже в коде мы сможем ссылаться на него вот так: #BLG3_SelectInventTable. Второе, такой макрос содержит макропараметры, у нас их два - %1 (в нем будет табличная переменная) и %2 (для имени поля в таблице). В тех местах, где находятся такие пары символов будет подставлено то, что указано в скобках вызова макроса при его использовании. То есть, после компиляции текст джоба будет выглядеть так: static void BLG3_Job(Args _args) {   InventTable inventTable1;   select ItemGroupId from inventTable1;   print inventTable1.ItemGroupId;   select ItemId from inventTable1;   print inventTable1.ItemId;   pause; }

Тот макрос, что был нами создан называется «stand-alone macro», по русски — «Стоят девчонки, стоят в сторонке, платочки в руках теребя». Или просто «автономный макрос».

среда, 18 июля 2007 г.

Терминология: компания

[id:012]

«Компания» в терминах Аксапты есть уникальный набор данных.

Работая в системе, ты всегда находишься в какой-то компании. Ее название отображается в строке состояния, стоит щелкнуть там два раза и появляется окно перехода в другую компанию: Диалог выбора компании

А если говорить по-простому, то все как в жизни: у каждой компании есть свои клиенты, свои заказы на покупку, свои продажи, бухгалтерия и персонал. Ну а Аксапта позволяет хранить данные для каждой компании в одной и той же базе. И когда вы переключаетесь в другую «компанию», то отображаются только ее данные, словно есть только она одна.

Этот удобный механизм позволяет отечественным предпринимателям вести дела одновременно в двух вариантах: а) «в белую», т.е. для налоговой инспекции, б) «в черную» как реальное отражение дел фирмы.

Другой вариант: есть холдинг, в котором несколько компаний. В Аксапте вы сможете вести все компании холдинга.

Как это выглядит с точки зрения программиста. Каждая (ну или почти каждая) таблица имеет еще одно поле — код компании. И всякий раз, когда пользователь обращается к данным, происходит автоматическая незаметная фильтрация записей по текущей компании.

Итог:

Аксапта — компанейская такая система.

Система: архитектура 2

[id:011]

Про AOS (Axapta Object Server).
К AOS-у подключаются клиенты, требуют от него данных и кода. А он берет информацию из базы данных и код бизнес-логики из AOD, и возвращает это добро клиентам. Вот такой он рулевой.

Что дает этот промежуточный слой:

  1. Кэширование объектов
    (Восстановление кэша приложения клиента при перезагрузке. Существенно уменьшает время загрузки для часто используемых объектов)
  2. Кэширование данных
  3. Администрирование
    (Единая точка администрирования клиентов, контроль клиентских сессий)

Тюнинг авто

Рядом с нашим офисом обитает контора, специализирующаяся на тюнинге, причем тюнинге автомобилей Митсубиси, причем тюнинге автомобилей Митсубиси Лансер Эволюшн.

вторник, 17 июля 2007 г.

Казань

Моя женщина - позитивный элемент жизни - вытащила в Казань.

Ехать 12-13 часов от Москвы.
Железнодорожный вокзал аккуратный, абсолютно не выглядит обосаным и облеванным. И какой-то совсем провинциальный для крупного города.
Хороший город. Зарплаты небольшие, челябинские: хорошая для одного человека – 15 тысяч рублей в месяц.

В Казани нужно: поесть чак-чак, посетить казанский Кремль (тот, что Иван Грозный брал).

пятница, 13 июля 2007 г.

Система: выполнение команд при запуске 3

Последовательность вызова методов при запуске Axapta [id:007]

Попробуем что-нибудь посложнее: создание класса, дочернего от SysStartupCmd. Идя таким путем, мы сможем влезть в области, помеченные розовым на диаграмме.

  1. Начинаем, как обычно, с создания проекта и ветки «Classes» в нем. Пустой проект JS_Blog006
  2. Создаем класс – наследник от SysStartupCmd. Внимание: имя должно начинаться на «SysStartupCmd», это правило хорошего тона (Best Practices). Я назвал его как "SysStartupCmdHelloWorld_JS"; суффикс "JS" прилепил, чтобы лишний раз показать, что это мое, а не какого-то датского программиста. Класс-наследник от SysStartupCmd
  3. Перегрузи метод infoRun() и напиши приветственное сообщение. Вообще можешь перегрузить любой из той четверки методов (см. диаграмму). Оставить здесь super() или нет – решать тебе. Код нашего метода infoRun() Здесь "startupCmd" - поле базового класса SysStartupCmd, в котором сохраняется строка параметров запуска. И у нас есть доступ к ней, мы же как-никак наследники.
  4. Идем в базовый класс – в SysStartupCmd, в его статический метод construct() добавляем код в ветку по-умолчанию для ветвления switch (участок, который был добавлен, выделен зеленой рамкой). Замечу, что на данном этапе мы поменяли один из классов системы. По правилам хорошего тона ты должен добавить ссылку на класс SysStartupCmd в дерево своего проекта. Таким образом показывается, какие объекты в процессе работы над проектом были затронуты.
  5. Все, закрывай систему и запусти снова. Результат? Ничего! Почему? Снова читаем диаграмму: пункты 1, 2, 5, 6, 8 и 10 выполняются ТОЛЬКО, если строка параметров запуска системы не была пустой. А она у нас пустая. Исправь ошибку (см. первый блог цикла): пропиши строку параметров запуска в конфигураторе клиентской части. И снова перезапусти систему. Я написал свой ник и нарвался на "Hello". Результат

Если не понятно, что я делал, снова посмотри диаграмму (самый первый рисунок).

Общее: создание группы в проекте

[id:017]

Создай новый проект с именем "ProjectTemplate". Щелкни правой кнопкой на проекте, пункт «Создать», строка «Group». На созданной группе щелкни правой кнопкой и выбери «Свойства»; откроется панель свойств. Если ты, как и я, считаешь, что с мозгом ничего не станет, если запомнить еще одно сочетание клавиш, то, пожалуйста: Alt+Enter — открыть панель свойств текущего объекта.

Задай свойства: ProjectGroupType = DataDictionary Name = DataDictionary

Шаблон дерева проекта Ты только что сделал в своем проекте группу. Дальнейшее разжевывание и отрыгивание информации в твоей клювик я прекращаю, и, уповая на твою разумность, Человек Разумный, прошу: воссоздай в своем проекте приведенное на рисунке. Соблюдай порядок расположения групп.

Внимание!
Правило хорошего тона (Best Practices): для каждого проекта, с которым ты работаешь, воссоздавай структуру, подобную AOT. Естественно, не надо создавать все группы, которые есть в AOT, — только те, что используются тобой. Зачем. Потому что единообразно. Удобно работать, когда по кучкам. Если еще нет, значит придет позже осознанная необходимость порядка.

Воссоздавать структуру всякий раз — лучше сразу пойти регулировщиком натяжения колесных спиц на Ижевском мотоциклетном заводе. Поэтому, не тронь более проект «ProjectTemplate». Это будет наш шаблон для вновь создаваемых проектов.

Создание копии проекта Как использовать шаблон.
Щелкаешь правой клавишей на проекте и выбираешь пункт «Дублировать». Новый проект появится; переименовывай и используй.

Про регулировщиков натяжения колесных спиц.
Мужская нервная система отлична от женской: плохо переносит монотонную работу.
Теперь представь себе мотоциклетное колесо, сколько там десятков спиц? Сидит рабочий, в руках устройство с моторчиком. Эту спицу чуть натянуть, другую — чуть ослабить. Спица за спицей, спица за спицей. А потом следующее колесо, и снова.

Общее: создание проекта 1

[id:010]

Проект — есть набор объектов, над которыми вы работаете. Другими словами, проект — это словно АОТ в уменьшенном масштабе.

Как создать проект.
Список проектов Окно нового проекта Нажимаете кнопку на панели инструментов (ту, что обведена овалом на рисунке). Появится окно "Projects".
В нем щелкните правой кнопкой на группе "Private", пункт "Создать", "Проект". Появиться новый проект с именем по умолчанию.
Переименуйте проект в «Blog10» (щелчок правой кнопкой, пункт «Переименовать»). Откройте его в отдельном окне (снова щелчок правой кнопкой, пункт «Открыть»).

Заметили, что в окне Projects содержится две подчиненных папки — Private и Shared.
Чем отличаются типы проектов Private и Shared?

Проект, помещенный в папку Private, доступен только пользователю, создавшему его. Проекты из папки Shared доступны всем. Разницу можно почувствовать, если зайти в домен Active Directory под другим пользователем.

Продолжение следует ...

Система: выполнение команд при запуске 2

Последовательность вызова методов при запуске Axapta [id:006]

Первый способ выполнить свой код во время запуска системы - поместить его в метод startupPost() классов Application и/или Info (на диаграмме выделены зеленым).

Итак, попишем маленько. Открывайте AOT (репозитарий прикладных объектов), ветка "Classes", класс "Info", метод "startupPost()" и в нем запиши следующий код: Пишем код, выполняемый при запуске системы Откомпилируй введеное. Выходи из системы и снова войди, должен увидеть следующее: Сообщение при запуске системы

Метод curuserid() возвращает строку с идентификатором текущего пользователя. Метод info() показывает информационное сообщение, в качестве параметра ему передается строка, которую нужно вывести.

среда, 11 июля 2007 г.

Система: выполнение команд при запуске 1

Последовательность вызова методов при запуске Axapta

[id:005]
Иногда нужно сделать что-то во время запуска системы. Этому и посвящаются несколько следующих статей.
Посмотрите рисунок слева. Это UML-диаграмма типа "Последовательность" (читается сверху-вниз), изображен кусок процесса запуска системы, в котором ты можешь полазить и сделать что-то свое. Места возможного приложения шаловливых ручек помечены розовыми и зелеными областями. В системе Axapta есть базисные (fundamental) классы, к ним относятся - Application и Info.
Сначала выполняется метод Application.startup(). И в нем..
  1. ...вызывается статический метод SysStartupCmd::construct(), в котором анализируется строка параметров запуска системы. В зависимости от ее содержимого создается дочерний от SysStartupCmd класс. Имена всех дочек начинаются на "SysStartupCmd".
  2. Вызывается метод applInit() класса, дочернего от SysStartupCmd.
  3. Время работать методу startup() родительского для Applicatioin класса.
  4. Вызов метода Application.startupPost().
  5. Вызывается метод applRun() класса, дочернего от SysStartupCmd.

    Метод Application.startup() закончился. И наступает время выполняться Info.startup():
  6. Тоже самое, что и в пункте 1
  7. Вызывается метод infoInit() класса, дочернего от SysStartupCmd
  8. Время работать методу startup() родительского для Info класса.
  9. Вызов метода Info.startupPost().
  10. Вызывается метод infoRun() класса, дочернего от SysStartupCmd

Обрати внимание, что пункты 1, 2, 5, 6, 8 и 10 выполняются ТОЛЬКО, если строка параметров запуска системы не была пустой. Чтобы задать эту строчку, иди в "Панель управления" операционной системы, пункт "Администрирование", "Microsoft Dynamics AX Configuration Utility". Откроется окно с настройками клиентской части системы Axapta; на рисунке овалом выделено поле, куда нужно ввести параметры запуска системы:

А что вообще происходит? Если честно, то я не знаю, но... В методе Application.startup() происходит инициализация серверной части для текущей сессии, а в Info.startup() - клиентской части.

PS: возврат какого-либо дочернего класса из статического метода construct() базового класса - это из "Best Practices of Axapta programming", т.е. передовая практика программирования в Аксапте. Об этом расскажу потом.

вторник, 10 июля 2007 г.

AOT - Application Object Tree

[id:004]

Система Axapta состоит из элементов — форм, запросов, программного кода, таблиц, типов данных —, и все это сгруппировано в виде AOT или Axapta Object Tree или Репозитарий прикладных объектов. Это просто дерево ВСЕХ объектов системы.

Посмотри на рисунок: в AOT элементы одного типа находятся в одной ветке. Например, в ветке "Forms" находятся все формы; в ветке "Data Dictionary" спрятались подветки "Tables" (для таблиц с данными), "Base Enums" (для перечислений).

Кнопка, обведенная кружком на рисунке, открывает AOT. Горячая клавиша для этого действия - Ctrl-D.

воскресенье, 8 июля 2007 г.

Система: архитектура 1

[id:009]

Начиная с 4-ой версии система имеет только трехслойную архитектуру: Трехуровневая архитектура

Client — клиентская часть системы, реализующая пользовательский интерфейс.
Application Object Database (AOD) — библиотека приложения, набор файлов, содержащих скомпилированный код объектов приложения, реализующий бизнес-логику системы. Известен также под именем "application file server".
Database — реляционная база данных MS SQL либо Oracle.
Axapta Object Server (AOS) — сервер приложения, координатор запросов клиентов. Берет из AOD исполняемый код с бизнес-логикой системы, а у базы данных — информацию; и раздает это клиентам.

Итог:
  1. Данные системы хранятся в базе данных
  2. Код приложения хранится на файл-сервере (AOD)
  3. AOD — это как Санчо Пансо, AOS — Дон Кихот. Один тащит все на себе, другой — решает проблемы.

Microsoft Dynamics AX

[id:033]

Система Axapta — это учетная система для автоматизации деятельности предприятий.
На момент написания статьи называется Microsoft Dynamics AX. И последняя версия на август 2007 года — четвертая, с сервис-паком номер 2.

Раньше называлась как Microsoft Business Solutions Axapta, еще раньше — Damgaard Axapta.

Начиная с четвертой версии, система имеет только трехслойную архитектуру и сильно интегрирована с Active Directory. Из этого, например, следует, что ты не сможешь установить систему на машину с операционной системой Windows XP Home Edition, так как там нет возможности включить компьютер в домен.

вторник, 3 июля 2007 г.

Система: макросы 1

[id:002]

Создайте новый job с именем «BLG_Job1» и наберите следующий код в теле джоба: Код, который нужно ввести Что заметит программист C++/C#?

  1. Объявление целочисленной переменной "i" не отличается от конструкции в Си
  2. Оператор "switch" абсолютно идентичен конструкциям в C++/C#
  3. Использование "break" по окончании ветки ветвления "case" обязательно, иначе будут выполнены команды следующей ветки
  4. Есть ветвление по-умолчанию — по ветке"default".

Теперь про макроконстанты. Здесь объявляется локальная макрокоманда. Локальная — потому что внутри функции. Используется конструкция #DEFINE, после которой, через точку, идет имя макроконстанты "MACRO_CONST". А в конце строки точку с запятой не ставим, хотя рука моя постоянно норовит это сделать.
Чтобы обратиться к макроконстанте ставим решетку и имя.

Как ты думаешь что выдаст программа?
Выдаст она цифру 1. Потому что макросы обрабатываются еще на этапе компиляции, а не во время исполнения кода, макрокоманды просматриваются последовательно сверху-вниз и во время исполнения джоба он будет выглядеть так: static void BLG_Job1(Args _args) { int i = 3; switch(i) { case 1: break; case 3: break; default: } print 1; pause; } , вне зависимости от того по какой ветке в switch мы пройдем.

Итог

Макроконстанты объявляются с помощью директивы #DEFINE

Форма: запуск с параметрами

[id:001]

Стандартный код для запуска формы с передачей параметров: Args args = new Args(); FormRun formRun; // настроить параметры вызова формы: // как ее зовут, кто посмел ее вызвать args.name(formstr(NameOfTheForm)); args.caller(this); /* Создание, инициализация, запуск */ formRun = classFactory.formRunClass(args); formRun.init(); formRun.run(); // ждем, пока пользователь завершит работу с формой, // и только потом продолжаем formRun.wait(); здесь NameOfTheForm — форма (ее свойство Name), которую нужно открыть; заметь, что имя пишется без кавычек.

воскресенье, 1 июля 2007 г.

Аренда квартиры в Москве

Снять квартиру в Москве, естественно, дорого, дружочеГ. Я снимаю квартиру в ЮЗАО (юго-западный административный округ) за 20 тысяч рублей в месяц. Круто, да? Это после 5 тысяч в месяц за квартиру в Челябинске, причем в очень хорошем районе (хотя там присутствовала доля везения).

Быстро найти квартиру можно через агентство недвижимости. Быстро – это за один день. Крупные агенты Москвы – «Инком» и «Миэль Недвижимость», - но они предлагают не самые дешевые варианты (это мое ощущение). Как вариант – сайт «cian.ru». Там агенты вывешивают свои объявления.

Агенту платишь премию, равную полной стоимости месячной аренды. Можно договориться и заплатить меньше, но в том случае, если скажешь «ДА» на первом или втором показе, т.е. если с тобой не долго возились. Платишь только тогда, когда он подберет тебе вариант, съездит с тобой и покажет квартиру, вы оформите сделку с хозяином квартиры. Вот тогда и плати. В случае других вариантов типа «гони тысячу рублей и мы дадим список адресов», посылайте таких умников в сторону леса. Можно не через агентство, тогда будешь искать где-то месяц или два.

Обычно, при заключении договора платишь за месяц вперед. Плюс к этому хозяин может попросить некие «страховые», равные, например, половине арендной платы. Страховые - на тот случай, если ты вдруг исчезнешь и прихватишь с собой тот самый продавленный диван поносно‑зеленого цвета, разобьешь драгоценное трюмо 1974 года выпуска со сломанной ножкой, скрутишь все краны и, само собой, уволочешь овальное зеркало в позорной чугунной раме. Особо оборзевшие берут за квартал вперед; наверное, такие люди тоже должны идти лесом.

Подведем итог. Лучшие районы Москвы: Центр, Запад, ЮЗАО. Остальное – хуже. Абсолютный кал – Восток (наверное, сказалось соседство с благородным городом Люберцы). Стоимость квартиры сильно зависит от близости к метро. Не стоит недооценивать этот фактор. С каждой пересадкой метро‑автобус‑трамвай‑троллейбус ты будешь терять деньги, время и свою жизненную энергию. А Москва задает высокий стандарт емкости твоей батарейки. Снять комнату в городе – от 6 тысяч, однокомнатную в городе – от 15 тысяч, двух комнатную в городе – от 18 тысяч. Можно сэкономить и жить в пригороде, тогда однокомнатная квартира может сравниться со стоимостью комнаты в Москве. Но опять же – это бОльшая усталость и потеря времени.

А вообще, москвичи – зажравшиеся товарищи: имея две квартиры, могут и не работать.

PS: на сладкое «Поиск квартиры через cian.ru», подсказанный моим знакомым Сергеем.

  1. Выбираешь на сайте подходящий вариант
  2. Если не указан номер дома, то звонишь агенту и под любым предлогом узнаешь у него заветную цифру дома.
  3. Едешь по адресу и расклеиваешь на всех подъездах объявление о продаже с указанием телефона и емкой фразой «посредники пусть курят бамбук».
  4. Этаж квартиры всегда указывается в объявлении об аренде. Поднимаешься на этот этаж в каждом подъезде и снова клеишь объявления.
  5. И так далее. Пока не найдешь.

Удачных тебе поисков и попутных душных сквозняков в метро!