Dynamics AX Blog - Dynamics AX 2009 - Seite 7

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

RSS-Feed dieser Version

Berichte lassen sich nicht über die Stapelverarbeitung ausführen

Wenn bei einem Benutzer der Register Stapel beim Aufruf eines Berichtes nicht angezeigt wird, kann dies u.U. daran liegen, daß der Benutzer keine oder unzureichende Berechtigung für den Sicherheitsschlüssel Stapelverarbeitungsbericht (SecurityKey BatchReport) hat.


 


 
 

Berechtigung eines Benutzers für einen Sicherheitsschlüssel abfragen

Mit diesem Stückchen Code kann man in Dynamics AX prüfen, welche Berechtigung ein Benutzer für einen bestimmten Sicherheitsschlüssel (Securitykey) hat.

static void GetSecurityKeyAccess4User(Args _args)
{
    Dictionary          Dictionary = new Dictionary();
    securityKeyId       securityKeyId;
    SecurityKeySet      securityKeySet = new SecurityKeySet();
    UserId              userId = 'user1';
    SelectableDataArea  dataArea = 'ceu';
    AccessType          accessType;
    ;

    securityKeyId = Dictionary.securityKeyName2Id("BatchReport");

    securityKeySet.loadUserRights(userId, dataArea);

    AccessType = securityKeySet.access(securityKeyId);

    info(enum2str(AccessType));
}

 
 

Notizen zu Systemdatum und -zeit

Im folgenden sind einige Gedankennotizen zum Thema Datum und Uhrzeit in Dynamics AX notiert.

In allen mir bekannten Versionen von Dynamics AX bzw. Axapta gibt es die nachstehenden Funktionen:

Funktionsaufruf Beschreibung
today() Datum des Clients
systemDateGet() Sitzungsdatum von AX
timeNow() Zeit des Clients

Ab Dynamics AX 2009 stehen u.a. zusätzliche folgende Funktionen zur Verfügung: 

Funktionsaufruf Beschreibung
DateTimeUtil::getSystemDateTime() Sitzungsdatum/-zeit von AX in koordinierter Weltzeit 
DateTimeUtil::applyTimeZoneOffset
(
    DateTimeUtil::getSystemDateTime(),
    DateTimeUtil::getUserPreferredTimeZone()
)
Sitzungsdatum/-zeit von AX für die aktuelle Zeitzone des Benutzers
 DateTimeUtil::date(_utcDateTime) Wandelt einen UTC-Datetime-Wert in ein Datum um

In allen bisherigen Dynamics AX-Versionen wird das Systemdatum und die Systemzeit von der Zeit des Clients initialisiert. Diese Werte kann sich der Benutzer - entsprechende Rechte vorausgesetzt - jederzeit selbst ändern (die Uhrzeit allerdings erst seit Dynamics AX 2009). Sie gelten aber nur für die aktuelle Sitzung und nur für diesen Benutzer.
 
Übrigens: Erhält man unter AX 2009 beim Starten eines AX-Clients die nachstehende Fehlermeldung, sollte man die Zeitzone des aktuellen Benutzers in den Benutzeroptionen prüfen.

Die Zeitzone des lokalen Comuters stimmt nicht mit den Einstellungen für die bevorzugte Zeitzone überein.

 


 
 

Druckeinstellungen und Filterkriterien eines Reports vorbelegen II

Wie startet man einen Bericht, bei dem eine von RunBaseReport abgeleitete Klasse vorgeschalten ist, per X++ und gibt diesem Bericht bereits den Query und die Druckeinstellungen vor?

Wer sich diese Frage schon einmal stellen musste, für den liefert dieser Blogbeitrag vielleicht einen Lösungsansatz:

static void setPrintJobSettingsQuery4ReportClass_II(Args _args)
{
    custReport          custReport = new custReport();
    printJobSettings    printJobSettings = new printJobSettings();
    ;
    custReport.makeReportRun();

    // Modify Query
    sysQuery::findOrCreateRange(custReport.reportRun().query().dataSourceTable(tableNum(custTable)), fieldNum(custTable, custGroup)).value(queryValue('10'));
    custReport.reportRun().query().interactive(false);
    // Create printJobSettings
    printJobSettings.setTarget(PrintMedium::File);
    printJobSettings.format(PrintFormat::PDF);
    printJobSettings.fileName(@"C:\Temp\CustTableReport.pdf");

    // Apply printJobSettings
    custReport.reportRun().printJobSettings(printJobsettings.packPrintJobSettings());
    custReport.reportRun().report().interactive(false);  // Disable default printer-dialog
    custReport.reportRun().run();
}

Obiger Code instanziiert ein Objekt der Klasse custReport, deren wesentliche Methoden wie folgt aussehen:

class CustReport extends runBaseReport
{
}

 

public identifiername lastValueElementName()
{
    identifiername ret;

    //ret = super();

    ret = reportStr(Cust);

    return ret;
}

 

static ClassDescription description()
{
    return "Custreport";
}

 

static void main(Args args)
{
    CustReport  CustReport;
    ;
    CustReport = new CustReport();
    if (CustReport.prompt())
    {
        CustReport.run();
    }
}

 
 

Tabellen mit doppelten RecIDs ermitteln

Wenn man in Dynamics AX (4.0 bzw. 2009) einmal in die Verlegenheit kommen sollte, prüfen zu müssen, ob es Tabellen mit doppelten RecIDs gibt, kann folgendes SQL-Script dabei behilflich sein:

use ax2009_standard_sp1

set nocount on

declare @tableName char(100)
declare db_cursor CURSOR FOR 
 select name from dbo.sysobjects
 where xtype = 'U'
 and name <> 'ROWSTAT'
 and name <> 'ROWSTATUS'
 and name <> 'SQLSYSTEMVARIABLES'
 and name <> 'SYSTEMSEQUENCES' -- SYSTEMSEQUENCES enthält immer doppelte RecIDs
 order by name asc

-- Temporäre Tabelle aufbauen
IF OBJECT_ID(N'tempdb..#tmp_duplrecid', N'U') IS NOT NULL
 begin
 drop table #tmp_duplrecid
 end

create table #tmp_duplrecid (tablename char(100), recordcounter bigint)   

OPEN db_cursor  
FETCH NEXT FROM db_cursor INTO @tableName  

WHILE @@FETCH_STATUS = 0  
 BEGIN  
  -- Tabellen mit doppelten RecIds ermitteln
  exec('insert into #tmp_duplrecid select ''' + @tableName + ''', COUNT(*)' +
    ' from ' + @tableName +
    ' group by RECID ' +
    ' having COUNT(*) > 1')
       
  FETCH NEXT FROM db_cursor INTO @tableName  
 END  

CLOSE db_cursor  
DEALLOCATE db_cursor

set nocount off

-- Tabellen mit doppelten RecIDs
select 'Tabelle enthält doppelte RecIDs: ' + tablename
from #tmp_duplrecid


 


 
 

Report auf Basis eines Query erstellen

Die Feldgruppe AutoReport einer Tabelle und deren Verwendung beim Drucken von Daten aus einem Formular heraus sollte wohl jedem Dynamics AX-Entwickler bekannt sein. Auf Basis dieser Standard-Funktionalität habe ich versucht, selbst einen Report per X++ auf Basis eines Query zu erstellen.

static void createReportFromQuery(Args _args)
{
    query                   query;
    report                  report;
    reportDesign            reportDesign;
    reportRun               reportRun;
    reportSection           reportSection;
    sysReportRun            sysReportRun;
    reportName              reportTemplateName = 'FrontPage';
    reportAutoDesignSpecs   reportAutoDesignSpecs;
    int                     ds;
    int                     f;
    printJobSettings        printJobSettings = new printJobSettings();
    ;

    // Build query
    query = new query();
    query.addDataSource(tableNum(vendTable));

    query.dataSourceTable(tableNum(vendTable)).addRange(fieldNum(vendTable, vendGroup)).value('10');

    // Add Fieldlist
    query.dataSourceTable(tableNum(vendTable)).addSelectionField(fieldNum(vendTable, accountNum));
    query.dataSourceTable(tableNum(vendTable)).addSelectionField(fieldNum(vendTable, name));
    query.dataSourceTable(tableNum(vendTable)).addSelectionField(fieldNum(vendTable, vendgroup));

    // Build printJobSettings
    printJobSettings.setTarget(PrintMedium::Screen);
    printJobSettings.format(PrintFormat::PDF);
    printJobSettings.fileName(@"C:\Temp\TempReportFromQuery.pdf");

    // Create report
    if( hasSecurityKeyAccess(securityKeyNum(SysDevelopment),
        AccessType::Edit))
    {
        report = new report();

        sysReportRun        = classfactory.reportRunClass(new Args(reportstr(SysReportAuto)));
        sysReportRun.init();

        sysReportRun.query(query);
        if (!sysReportRun.queryRun())
        {
            sysReportRun.queryRun(new SysQueryRun(query));
        }

        sysReportRun.queryRun().query().interactive(false);
        Report.interactive(!printJobSettings);            

        Report.query(sysReportRun.queryRun().query());

        reportDesign = report.addDesign();
        reportDesign.caption("TmpReportFromQuery");
        reportDesign.reportTemplate(reportTemplateName);
        reportDesign.orientation(printerOrientation::Auto);

        reportAutoDesignSpecs = reportDesign.autoDesignSpecs();

        // Add body
        for(ds = 1;ds <= sysReportRun.queryRun().query().dataSourceCount(); ds++)
        {
            reportSection = reportAutoDesignSpecs.addSection(reportBlockType::Body, sysReportRun.queryRun().query().dataSourceNo(ds).table());
            reportSection.arrangeMethod(arrangeMethod::Vertical);

            for(f=1;f<=sysReportRun.queryRun().query().dataSourceNo(ds).selectionCount();f++)
            {
                reportSection.addControl(sysReportRun.queryRun().query().dataSourceNo(ds).table(), sysReportRun.queryRun().query().dataSourceNo(ds).fields().field(f));
            }
        }

        // Run the report
        reportRun = new reportRun(report);
        reportRun.fetch();

        // Print the report
        if(printJobSettings)
        {
            reportRun.printJobSettings(printJobSettings.packPrintJobSettings());
        }
        reportRun.print();
    }
}

Das Ergebnis des obigen Codes ist ein sehr einfacher Report:


 
 

Arbeiten mit dem aufrufenden Objekt einer Form (Caller) II

Um in einem Objekt auf das aufrufende Objekte zuzugreifen, habe ich anhand von einigen Zeilen Code ja schon demonstriert (siehe hier und hier). Dabei hatte ich aber immer ausser Acht gelassen, daß das aufrufende Objekt ja auch eine Klasse sein kann.

Nun also hier ein entsprechendes Beispiel:

if (element.args() && 
    element.args().caller() && 
    classidget(element.args().caller()) == classnum(nameOfClass )) 
{
    nameOfClass = element.args().caller();
    someValue = nameOfClass.someMethod();
}

 
 
Seiten « 1 ... 4 5 6 7 8 9 10 ... 20 » 

 

 
 
 
Beiträge des aktuellen Monats
April 2024
MoDiMiDoFrSaSo
1234567
891011121314
15161718192021
22232425262728
2930 
 
© 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