Dynamics AX Blog - Dynamics AX 2012 - Seite 26

Momentan angezeigt werden nur Beiträge, welche für die Dynamics AX-Version »Dynamics AX 2012« relevant sind. Filter entfernen

RSS-Feed dieser Version

X++ -Statement generieren um Datensätze anzulegen

Vor kurzem hatte ich die Notwendigkeit einige Datensätze von einer AX-Umgebung in eine andere zu kopieren. Es ging um eine sehr flache Tabelle (d.h. ohne großartige Referenzen auf andere Tabellen oder Datensätze), wodurch ich folgenden Job dafür nutzen konnte.

Der Job durchläuft ein Select-Statement (ganz am Ende des Jobs) und kopiert mir in die Zwischenablage ein X++-Statement, mit welchem man die Datensätze - beispielsweise über einen eigenen Job - einfügen kann.

Inspiriert ist der Code übrigens von der Methode buildInsertScript() des Formulares SysRecordInfo.
 

static void buildInsertScriptAX2009(Args _args)
{
    CustGroup CustGroup;

    #define.indent('    ')

    SysDictTable dictTable;
    Counter     fieldCounter;
    Counter     arrayCounter;
    DictEnum    dictEnum;
    DictField   dictFieldTemp;
    DictField   dictFieldArray;
    str         fieldValue;
    TextBuffer  textBuffer;
    Source      source;

    boolean setFieldValue(fieldId _fieldId, common _common)
    {
        boolean ret = true;

        fieldValue = "";

        if (dictFieldTemp.baseType() != Types::Container)
        {
            fieldValue = strfmt("%1", _common.(_fieldId));
        }

        switch (dictFieldTemp.baseType())
        {
            case Types::String :
                fieldValue = strReplace(fieldValue, '\n', '\\n');
                fieldValue = '\"' + fieldValue + '\"';
                break;

            case Types::Container :
                fieldValue = '[' + fieldValue + ']';
                break;

            case Types::Enum :
                dictEnum = new DictEnum(dictFieldTemp.enumId());
                fieldValue = dictEnum.name() + '::' + dictEnum.index2Symbol(_common.(_fieldId));
                break;

            case Types::Real :
                fieldValue = num2str(_common.(_fieldId), 2, -1, 1, 0);
                break;

            case Types::Date :
                fieldValue = date2str(_common.(_fieldId), 123,2,4,2,4,4);
                if (fieldValue == '')
                {
                    ret = false;
                }
                fieldValue = strReplace(fieldValue, '/', '\\');
                break;

            case Types::UtcDateTime :
                fieldValue = DateTimeUtil::toStr(_common.(_fieldId));
                if (fieldValue == '')
                {
                    ret = false;
                }
                break;
        }
        return ret;
    }

    void loopRecord(common _common)
    {
        ;
        source += #indent + strfmt('%1.clear();\r\n', dictTable.name());

        for (fieldCounter = dictTable.fieldNext(0); fieldCounter > 0; fieldCounter = dictTable.fieldNext(fieldCounter))
        {
            dictFieldTemp = new DictField(dictTable.id(), fieldCounter);

            if (dictFieldTemp.isSystem())
                continue;

            if (dictFieldTemp.arraySize() > 1)
            {
                arrayCounter = 1;
                while (arrayCounter <= dictFieldTemp.arraySize())
                {
                    dictFieldArray = new DictField(dictTable.id(), fieldId2Ext(dictFieldTemp.id(),arrayCounter));
                    if (setFieldValue(dictFieldArray.id(), _common))
                    {
                        source = source + #indent + strfmt("%1.%2 = %3;", dictTable.name(),
                                                                          dictFieldArray.name(DbBackend::Native, arrayCounter),
                                                                          fieldValue) + '\r\n';
                    }
                    arrayCounter++;
                }
            }
            else
            {
                if (setFieldValue(fieldCounter, _common))
                {
                    source = source + #indent + strfmt("%1.%2 = %3;", dictTable.name(), dictFieldTemp.name(), fieldValue) + '\r\n';
                }
            }
        }

        source += #indent + strfmt('%1.insert();\r\n', dictTable.name());
    }

    ;

    // Modify needed records here
    dictTable = new SysDictTable(tableNum(CustGroup));

    while select CustGroup
    {
        loopRecord(CustGroup);
    }

 

 

    textBuffer = new TextBuffer();
    textBuffer.setText(source);
    textBuffer.toClipboard();

    info("@SYS87601");
}

Das Ergebnis des Jobs ist in der Zwischenablage zu finden, und sieht beispielsweise wie folgt aus:

CustGroup.clear();
CustGroup.CustGroup = "K-DRITT";
CustGroup.Name = "Kunden Drittland";
CustGroup.ClearingPeriod = "";
CustGroup.PaymTermId = "";
CustGroup.TaxGroupId = "";
CustGroup.PaymIdType = "";
CustGroup.insert();
CustGroup.clear();
CustGroup.CustGroup = "K-EU";
CustGroup.Name = "Kunden EU";
CustGroup.ClearingPeriod = "";
CustGroup.PaymTermId = "";
CustGroup.TaxGroupId = "";
CustGroup.PaymIdType = "";
CustGroup.insert();
CustGroup.clear();
CustGroup.CustGroup = "K-INL";
CustGroup.Name = "Kunden Inland";
CustGroup.ClearingPeriod = "";
CustGroup.PaymTermId = "";
CustGroup.TaxGroupId = "";
CustGroup.PaymIdType = "";
CustGroup.insert();
 

In Dynamics AX 2012 sieht der gleiche Job etwas anders aus:

static void buildInsertScriptAX2012(Args _args)
{
    CustGroup CustGroup;
   
    #define.indent('    ')
   
    SysDictTable dictTable;
    Counter     fieldCounter;
    Counter     arrayCounter;
    DictEnum    dictEnum;
    DictField   dictFieldTemp;
    DictField   dictFieldArray;
    str         fieldValue;
    TextBuffer  textBuffer;
    Source      source;

    boolean setFieldValue(common _common, FieldName _fieldName, ArrayIdx _arrayIndex = 1)
    {
        boolean ret = true;
        fieldValue = "";

        if (dictFieldTemp.baseType() != Types::Container)
        {
            fieldValue = strFmt("%1", _common.getFieldValue(_fieldName, _arrayIndex));
        }

        switch (dictFieldTemp.baseType())
        {
            case Types::String :
                fieldValue = strReplace(fieldValue, '\n', '\\n');
                fieldValue = '\"' + fieldValue + '\"';
                break;

            case Types::Container :
                fieldValue = '[' + fieldValue + ']';
                break;

            case Types::Enum :
                dictEnum = new DictEnum(dictFieldTemp.enumId());
                fieldValue = dictEnum.name() + '::' + dictEnum.value2Symbol(_common.getFieldValue(_fieldName, _arrayIndex));
                break;

            case Types::Real :
                fieldValue = num2str(_common.getFieldValue(_fieldName, _arrayIndex), 2, -1, 1, 0);
                break;

            case Types::Date :
                fieldValue = date2str(_common.getFieldValue(_fieldName, _arrayIndex), 123,2,4,2,4,4, DateFlags::None);
                if (fieldValue == '')
                {
                    ret = false;
                }
                fieldValue = strReplace(fieldValue, '/', '\\');
                break;

            case Types::UtcDateTime :
                fieldValue = DateTimeUtil::toStr(_common.getFieldValue(_fieldName, _arrayIndex));
                if (fieldValue == '')
                {
                    ret = false;
                }
                break;
        }
        return ret;
    }
   
    void loopRecord(common _common)   
    {
        ;

        for (fieldCounter = dictTable.fieldNext(0); fieldCounter > 0; fieldCounter = dictTable.fieldNext(fieldCounter))
        {
            dictFieldTemp = new DictField(dictTable.id(), fieldCounter);

            if (dictFieldTemp.isSystem())
                continue;

            if (dictFieldTemp.arraySize() > 1)
            {
                arrayCounter = 1;
                while (arrayCounter <= dictFieldTemp.arraySize())
                {
                    dictFieldArray = new DictField(dictTable.id(), dictFieldTemp.id(), arrayCounter);
                    if (setFieldValue(_common, dictFieldArray.name(), arrayCounter))
                    {
                        source = source + #indent + strFmt("%1.%2 = %3;", dictTable.name(),
                                                                          dictFieldArray.name(DbBackend::Native, arrayCounter),
                                                                          fieldValue) + '\r\n';
                    }
                    arrayCounter++;
                }
            }
            else
            {
                if (setFieldValue(_common, dictFieldTemp.name()))
                {
                    source = source + #indent + strFmt("%1.%2 = %3;", dictTable.name(), dictFieldTemp.name(), fieldValue) + '\r\n';
                }
            }
        }

        source += #indent + strFmt('%1.insert();\r\n', dictTable.name());
    }
   
    // Modify needed records here   
    dictTable = new SysDictTable(tableNum(CustGroup));

    while select CustGroup
    {
        loopRecord(CustGroup);
    }
 

    textBuffer = new TextBuffer();
    textBuffer.setText(source);
    textBuffer.toClipboard();

    info("@SYS87601");
}

 
 

Tipps und Tricks zum Thema Kompilierung

Compiler output

Kompilieren gehört zum täglich Brot eines Entwicklers. Leider weist genau dieser Vorgang in Dynamics AX - nennen wir es - Besonderheiten auf.

Besonderheit 1: Kein Fortschrittsbalken

Wir kennen es alle, man kompiliert eine grössere Menge an Objekten oder vielleicht den ganzen AOT und möchte zumindest ungefähr wissen, wie lange dies noch dauert.

Standardmässig gibt’s es kaum eine Möglichkeit dies einzusehen, vor allem wenn der AX-Client seit dem Start der Kompilierung vielleicht schon "eingefroren" ist.

In vielen Fällen kann man [CTRL]+[PAUSE] drücken, dadurch wird die Kompilierung kurz angehalten und man kann im Client sehen, bei welchem Objekt man gerade ist. In dem Pause-Dialog sollte man natürlich tunlichst auf [NEIN] klicken, wenn man die Kompilierung danach fortsetzen möchte.

Kein echter Fortschrittsbalken, aber zumindest ein Indikator wo man gerade steht.


 
 

AX 2012: Druckverwaltung abhängig von den Daten einrichten

Man kann über die Druckverwaltungseinstellungen/Druckverwaltung von Dynamics AX Dokumente so einrichten, daß diese abhängig vom Dateninhalt auf einem anderen Drucker oder Druckmedium ausgegeben werden.

Dazu muss man einfach mit der rechten Maustaste beim jeweiligen Dokument den Menüpunkt Neu anwählen. Nun kann man in der Gruppe Bedingung Kriterien hinterlegen.

Sceenshot

In nachstehendem Beispiel werden beispielweise Auftragsbestätigungen mit einem Gesamtbetrag von mehr als 100 EUR gesondert verarbeitet.


 
 

AX 2012: Verwendung der Methode titleFields in Forms

In zahlreichen Formularen vom Typ Detailspage findet man einen Bereich, wie dem in folgendem Screenshot abgebildeten.

Screenshot

Dieser Bereich wird über die - meines Wissens nach undokumentierte - Methode titleFields() umgesetzt. Diese Methode liefert einen 60 Zeichen langen String.

Screenshot 


 
 

Text-Datei per X++ drucken

Ein kurzes Beispiel, wie man aus AX heraus via Notepad eine Text-Datei ausdrucken kann.

static void printTextFileFromAX(Args _args)
{
    WinAPI::shellExecute("c:\\windows\\system32\\NOTEPAD.EXE",  @'/pt "c:\temp\test.txt" "An OneNote 2010 senden"');
}

Hinweise: "An OneNote 2010 senden" ist dabei der Name des Druckers. Das Beispiel wurde in Dynamics AX 2012 verwendet, sollte allerdings auch in früheren Versionen verwendbar sein.


 
 

AX 2012: LedgerDimension generieren II

Update 11.05.2014: Da die unten stehende Code-Beispiele nicht in allen Applikationen zu funktionieren scheinen, habe ich unter folgendem Beitrag ein weiteres Code-Beispiel veröffentlicht.

Im folgenden ein kurzes Code-Snippet, welches zeigt wie man beispielsweise Finanzdimensionen mit einem Haupt-/Sachkonto zu einer RecId verbindet, welche beispielsweise als LedgerDimension in einer Sachkontenjournal-Zeile (Allgemeine Erfassung; LedgerJournalTrans.LedgerDimension) verwendet werden kann.

static void mergeDimensions(Args _args)
{
    SalesLine salesLine;
    MainAccount mainAccount;
    LedgerDimensionAccount ledgerDimensionAccount;

    // Get source dimension values (for example from SalesLine-Record)
    select firstonly salesLine
    where salesLine.SalesId == "20001"
       && salesLine.DefaultDimension;

    // Get main account
    mainAccount = MainAccount::findByMainAccountId('0500');

    // Merge main account and source dimension values and return RecId which can be used as ledgerDimension
    ledgerDimensionAccount = DimensionDefaultingService::serviceCreateLedgerDimension(mainAccount.RecId, salesLine.DefaultDimension);

    info(strFmt("DefaultDimension (Source RecId): %1 LedgerDimension (Merged RecId): %2", salesLine.DefaultDimension, ledgerDimensionAccount));
}

Das zweite Snippet macht prinzipiell das selbe wie oben, allerdings wird hier statt einem Haupt-/Sachkonto ein Debitorenkonto verwendet.


 
 

Markierte Datensätze eines Formulares verarbeiten/iterieren

Um in Dynamics AX die markierten Datensätze einer Formular-Datenquelle (FormDataSource) zu verarbeiten/iterieren kann folgendes Code-Beispiel helfen:

void markSelected()
{
    inventTrans inventTransSelected;
    inventTrans inventTrans4Update;

    ttsbegin;
    inventTrans4Update.setTmpData(inventTrans);    //DIES IST NUR BEI TEMPORÄREN TABELLEN NOTWEDNIG
    for (inventTransSelected = inventTrans_ds.getFirst(true) ? inventTrans_ds.getFirst(true) : inventTrans_ds.cursor();
         inventTransSelected;
         inventTransSelected = inventTrans_ds.getnext())
    {
        select firstonly forUpdate inventTrans4Update
        where inventTrans4Update.RecId == inventTransSelected.RecId;

        inventTrans4Update.Marked = NoYes::Yes;
        inventTrans4Update.update();
    }
    ttscommit;

    inventTrans_ds.executeQuery();
}

Im Beispiel werden die markierten Datensätze der Tabelle InventTrans durchlaufen und ein Feld Marked auf TRUE aktualisiert.

In Dynamics AX 2012 kann übrigens statt dessen auch die Klasse MultiSelectionHelper dafür verwendet werden.


 
 
Seiten « 1 ... 23 24 25 26 27 28 29 ... 38 » 

 

 
 
 
Beiträge des aktuellen Monats
Juni 2024
MoDiMiDoFrSaSo
 12
3456789
10111213141516
17181920212223
24252627282930
 
© 2006-2024 Heinz Schweda | Impressum | Kontakt | English version | Mobile Version
Diese Webseite verwendet Cookies, um Benutzern einen besseren Service anzubieten. Wenn Sie weiterhin auf der Seite bleiben, stimmen Sie der Verwendung von Cookies zu.  Mehr dazu