понедельник, 22 июля 2013 г.

Разное

Передача параметров в вызываемую форму:
http://axforum.info/forums/showthread.php?t=30177
http://www.axaptapedia.com/Passing_values_between_forms

Фильтрация на форме:
http://dynamics-ax-live.blogspot.ru/2010/03/how-to-filter-records-in-form-by-code.html

Раскраска грида:
http://daxguy.blogspot.ru/2007/04/coloring-grids-in-dax.html

Деактивация контрола (на active датасорса):
    Control.enabled(true);
    select count(RecId) from cSST where cSST.Row == Table_ds.cursor().getFieldValue("RecId");
    if(cSST.RecId <= 1) Control.enabled(false);

DateTime2Real:
public real DT2Real(utcDateTime _dt)
{
    str qwe;
    int wer;
    real ert;  
   
       qwe = DateTimeUtil::toStr(_dt);  
       qwe = strRem(qwe,"T");
       qwe = strRem(qwe,"-");
       qwe = strRem(qwe,":");
       wer = str2int(qwe);
       ert = wer/10000;    
       return ert;
}

Date2UTCDateTime:
public utcDateTime convertDToUtcDT(date simpleDate)
{
int timeOfDay;
UTCDateTime datetime;
;
timeOfDay = str2time('00:00:00');
datetime = DateTimeUtil::newDateTime(simpleDate, timeOfDay);
return datetime;
}

понедельник, 27 мая 2013 г.

Выполнение X++ кода в CLR - код может выполняться быстрее. Раза в три(!) быстрее...

Очень полезная статья, следуя которой можно запилить выполнение клиентского кода в CIL: http://daxmusings.codecrib.com/2011/08/x-in-net-clr-life-in-fast-lane.html

и при необходимости приаттачиться к процессу отладчиком VisualStudio

Вот здесь http://blogs.msdn.com/b/mfp/archive/2012/06/25/the-compare-tool-and-running-x-code-as-il.aspx есть небольшое сравнительное исследование быстродействия.

понедельник, 29 апреля 2013 г.

Создание master/detail формы

Часто возникающая задача - в верхней (левой) части формы список header'ов, а в нижней (или правой) части - список details'ов. Здесь популярно расписано решение: http://daxdave.blogspot.ru/2006/10/creating-headerdetail-based-linkage-on.html
PS да, и тут ни строчки кода ;)
 PPS  и вдогонку оставлю тут ссылочку про как сделать вертикальный сплиттер на форме:  http://dynamicsaxposed.wordpress.com/2011/08/17/how-to-make-vertical-splitter-on-forms-in-ax-2012/

среда, 24 апреля 2013 г.

Зависимые Lookup на форме

Возникла необходимость сделать серию из трёх зависимых полей, выбор значения в одном из них фильтрует значения во втором, выбор второго фильтрует третий. Азбучный пример из книги (перекрытие метода lookup) отлично подходит для поля StringEdit, но отказывается работать на ReferenceGroup. Для последнего необходимо перекрывать lookupReference.
public void lookup() //для StringEdit

воскресенье, 7 апреля 2013 г.

“Продвинутый” фильтр на форме

Microsoft Dynamics AX 2012 for Developers [AX 2012]
Форма позволяет фильтровать Grid различными способами, но нам захотелось сделать свой – по нажатию кнопки открывать дочернюю форму, в которой задать определенные поля, которые сформируют нужный Query.
Первая попытка – сделать extends RunBase класс, в котором создавать DialogField. Всё было б ничего, но не получилось следующее – хотелось вывести в выпадающем меню фильтра Name, а передать в query родительской формы RecId.
Вторая попытка – вызывать из формы всё тот же класс, сделать от этого класса форму, в которой можно разместить ReferenceField, который реализует нужный нам функционал…
Оба эти примера не доделаны, сюда скинул промежуточный итог.
Рабочий и самый простой вариант – одна простая форма. Тут её код:

public class FormRun extends ObjectRun
{
    Object caller;
    boolean activate;
}
void closeOk()
{
    super();
    caller = element.args().caller();
    caller.itemRangeValue(itemIdStringEdit.text());
    caller.subitemNumberValue(subitemNumberIntEdit.value());
    caller.subitemGroupValue(subitemGroupStringEdit.text());
    caller.subitemgoValue(subitemgoReferenceGroup.value());
    if (subitemgoYesNo.checked()) {
        caller.subitemgoYesNo(true);
    }
    caller.1stplaceValue(1stplaceReferenceGroup.value());
    caller.currentplaceValue(CurrentplaceReferenceGroup.value());
    caller.activateFilter(true);
    caller.update();
   ));
}

и код формы – caller’a:

SSRS Отчеты в Dynamics AX 2012

Developing Reports for Microsoft Dynamics AX in Visual Studio [AX 2012]

Очень полезный фрагмент книжки о разработке отчетов – позволяет быстро начать, даже если раньше вам не приходилось работать с Reporting Services + Dynamics.
Находится тут: http://www.slideshare.net/harshnmh/developing-ssrsreportsfordynamicsax
+для себя копия
Задача стояла следующая – необходимо разработать простой отчет, в котором на входе должен быть параметр, взятый из грида. На форме размещается кнопка, по нажатию на кнопку Action – class, код класса ниже:

class RdpReport extends SrsReportRunController
{
    #define.ReportName('QueryBasedReport.Report')
}
protected void prePromptModifyContract()
{
    this.setRanges(this.parmReportContract().parmQueryContracts().lookup(this.getFirstQueryContractKey()));
}
public static client void main(Args _args)
{    rdpReport controller = new rdpReport();
    controller.parmReportName(#ReportName);
    controller.parmArgs(_args);
    controller.startOperation();
}
private void setRanges(Query _query)
{
    real volumeRange;
    Report ReportLocal;
  
    if (this.parmArgs())
    {
                ReportLocal = this.parmArgs().record();
                volumeRange = ReportLocal.Volume;
    }
   
    if (volumeRange)
    {
        SysQuery::findOrCreateRange(
            _query.dataSourceTable(tableNum(Report)),
            fieldNum(Report, Volume)).value(int2str(volumeRange));
    }   
}

среда, 30 января 2013 г.

Получение данных из внешних БД


Рассмотрим пару вариантов работы с внешними БД.

Вариант 1: отобразить как список таблицу из внешней БД MS SQL, позволив пользователям работать с таблицей как со списком – просматривать, добавлять и удалять значения – строки.

Для этого нужно создать внешний тип контента в SP Designer:
ex1
ex2ex3

ex4
Выбрав “Подключиться с удостоверением пользователя”, мы сможем подключиться только к БД, расположенной на том же сервере, где находится БД SharePoint. При попытке подключения к какой-либо другой, получим ошибку, описанную вот тут:   http://www.spdoctor.net/Pages/message.aspx?name=login-failed-for-user-bdc
Как правило, подключение требуется к внешней БД, поэтому надо использовать 2й и 3ий варианты подключения. Эти варианты требуют идентификатора Secure Store – фактически это логин и пароль, в зашифрованном виде хранящиеся в специальной службе SharePoint. Создать Secure Store ID можно через “Центр Администрирования SharePoint” – “Управление приложениями-службами“. Там нужно найти “Приложение службы Secure Store” – называться оно может как угодно.
ВАЖНО: если таких служб 2 или более, обязательно выясните, какая из них используется веб-приложением “по умолчанию”. Сделать это можно здесь: “Центр администрирования - Сопоставления приложений-служб “. Именно её и нужно использовать для создания Secure Store ID.

ex5
По клику на “Создать” вызывается диалог, в котором создаются поля логина и пароля, затем можно задать эти логин и пароль, кликнув “Настроить” в блоке “Учётные данные”
Всё, SSID готов. Теперь можно указать его в поле “Идентификатор приложения SecureStore” и нам станут доступны таблицы внешнего источника данных. Для любой из них можно создать 5 типов операций:
ex6
Для того, чтобы отобразить содержимое таблицы как список – необходимо создать как минимум первые две операции. В создании нет ничего сложного – просто жмём Далее и Финиш.
Ещё один важный момент, без которого список не будет доступен – необходимо разрешить пользователям доступ к этому типу контента – это тоже делается в
“Центр Администрирования SharePoint” – “Управление приложениями-службами”, только теперь уже настраивается служба “Приложение-служба подключения к бизнес-данным”:
ex7
Как видим, этот вариант практически полностью (за исключением создания SecureStore) реализуем с помощью одного только SP Designer, однако имеет массу ограничений – нельзя таким образом работать с другими СУБД (например, Oracle), нельзя работать с объединением 2х и более таблиц – для этого нужно описывать модель работы с данными в коде, используя Visual Studio. В курсе 10175A SharePoint Application Development вторая лабораторная шестого урока посвящена именно такому созданию модели.

Вариант 2: доступ к внешней БД через powershell, работа с данными из БД как с объектами

Вот пример синхронизации списка SharePoint с данными из внешней БД Oracle.
Используется функция Get-DatabaseData, взято вот отсюда: http://technet.microsoft.com/ru-ru/magazine/hh855069.aspx
# Позволяет выполнять запросы к БД Oracle
function Get-DatabaseData {
[CmdletBinding()]
param (
  [string]$connectionString,
  [string]$query,
  [switch]$isSQLServer
)
if ($isSQLServer) {
  Write-Verbose 'in SQL Server mode'
  $connection = New-Object System.Data.SqlClient.SqlConnection
} else {
  Write-Verbose 'in OleDB mode'
  $connection = New-Object System.Data.OleDb.OleDbConnection
}
$connection.ConnectionString = $connectionString
#'Provider=OraOLEDB.Oracle;Data Source=(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=host.host.ru)(PORT=1521)))(CONNECT_DATA=(SID=SOMESID)));User Id=USERID;Password=PASSWORD;'
#$connectionString = 'Provider=OraOLEDB.Oracle;Data Source=(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=host.host.ru)(PORT=1521)))(CONNECT_DATA=(SID=SOMESID)));User Id=USERID;Password=PASSWORD;''
$command = $connection.CreateCommand()
$command.CommandText = $query
if ($isSQLServer) {
  $adapter = New-Object System.Data.SqlClient.SqlDataAdapter $command
} else {
  $adapter = New-Object System.Data.OleDb.OleDbDataAdapter $command
}
$dataset = New-Object System.Data.DataSet
$adapter.Fill($dataset)
return $dataset.Tables[0]
}
Источником данных может быть любая БД, разница только в строке подключения. Формат строки подключения для любой СУБД можно взять с http://connectionstrings.com/
Можно выполнять любые операции – INSERT, DELETE, CREATE и т.д. при наличии доступа к этой БД.
Ну и сам пример. Сравнивает данные о командах из таблицы БД с данными в списке “Alarm groups” по ID. Eсли команда переименована или создана, изменяет или создаёт новый элемент в списке. Если команда удалена – проверяет наличие связанных элементов из списка “Точки мониторинга” и при отсутствии связей удаляет элемент, иначе выдаёт оповещение:
$datarow = Get-DatabaseData -verbose -query "SELECT * FROM DUTY.group" -connectionString "Provider=OraOLEDB.Oracle;Data Source=(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=host.host.ru)(PORT=1521)))(CONNECT_DATA=(SID=SOMESID)));User Id=USERID;Password=PASSWORD;"
$site = new-object Microsoft.SharePoint.SPSite("http://mysite")
$web = $site.OpenWeb("myweb")
$list = $web.Lists["Alarm groups"]
[Microsoft.SharePoint.SPListItemCollection]$list_items = [Microsoft.SharePoint.SPListItemCollection]$list.Items;
$message = "Запускаем процедуру синхронизации. Проверяем наличие новых или переименованных команд..."
log "Аварийные команды" $message
for( $i=1; $i -le $datarow[0];$i++) {
    $bool = 0
foreach( $list_item in $list_items ) {
    if ($list_item["ID0"] -eq $datarow[$i].Item(0)) {
  if ($datarow[$i].Item(1) -eq $list_item["Title"]) {
            $bool=1
   continue
   }
  else {
   $list_item["Title"] = $datarow[$i].Item(1)
            $list_item["_x0413__x041a__x0414_"] = "http://www.site.ru?groupId="+$datarow[$i].Item(0)+", "+$datarow[$i].Item(1)
   update $list_item
   $message = "Команда"+" "+$datarow[$i].Item(0)+" "+"переименована из"+" "+$list_item["Title"]+" в "+$datarow[$i].Item(1)
   log "Аварийные команды" $message
            $bool=1
            continue
   }
        }
}
    if (!($bool)) {
       $message = "Команда"+" "+$datarow[$i].Item(0)+" "+$datarow[$i].Item(1)+" "+"добавлена"
    log "Аварийные команды" $message
       $list_item = $list.Items.Add()
       $list_item["ID0"] = $datarow[$i].Item(0)
       $list_item["Title"] = $datarow[$i].Item(1)
       $list_item["_x0413__x041a__x0414_"] = "http://www.site.ru?groupId="+$datarow[$i].Item(0)+", "+$datarow[$i].Item(1)
       update $list_item
    }
}
$message = "Проверяем наличие удалённых команд"
log "Аварийные команды" $message
for($c = $list_items.Count - 1; $c -ge 0; $c--) {
    $bool = 0
    for( $i=1; $i -le $datarow[0];$i++) {
        if ( $list_items[$c]["ID0"] -eq $datarow[$i].Item(0)) {
            $bool=1
            continue
            }
        }
    if (!($bool)) {
    $title = $list_items[$c]["Title"]
    $coll_item_name = ""
$order_listx = $web.Lists["Точки мониторинга"]
    $queryx = new-object Microsoft.SharePoint.SPQuery
    $queryx.query = "<Where><Eq><FieldRef Name='_x0410__x0432__x0430__x0440__x04' /><Value Type='Lookup'>$title</Value></Eq></Where>"
$collectionx = $order_listx.GetItems( $queryx )
    if( $collectionx.count) {
        foreach( $coll_item in $collectionx){
            $title = $coll_item["Title"]
            $id = $coll_item["ID"]
            $coll_item_name = $coll_item_name+"<br>"+"<a href='http://mysite/myweb/Lists/PointsMonitoring/DispForm.aspx?ID=$id'>$title</a>"
            }
        $message = "ВНИМАНИЕ! Команда"+" "+$list_items[$c]["Title"]+" "+"была удалена из http://www.site.ru/DutyList, но не может быть удалена из списка Аварийных команд, т.к. остались ТМ со ссылкой на нее: "+$coll_item_name
        log "Аварийные команды" $message
        }
    else {
        $message = "Команда"+" "+$list_items[$c]["Title"]+" "+"была удалена из списка Аварийных команд"
        log "Аварийные команды" $message
        $list_items.Delete($c)
        }
    }
}
$list.Update()
$message = "Процедура синхронизации завершена"
log "Аварийные команды" $message