Tuesday, May 22, 2018

Number sequence customization in Dynamics 365 for Finance and Operations


Create a number sequence in a standard module
  • Create new EDT
  • Add a new code block to the loadModule in the NumberSeqModuleXXX class
  • Add a new static method to the parameters table of the module to get the number sequence reference
Using Extension
[ExtensionOf(classStr(NumberSeqModuleCustomer))]
final class NumberSeqModuleCustTest_Extension
{
            protected void loadModule()
            {
                        NumberSeqDatatype datatype = NumberSeqDatatype::construct();
                        next loadModule();                        
datatype.parmDatatypeId(extendedTypeNum(TestId));
datatype.parmReferenceHelp(literalStr('Test ID'));
                        datatype.parmWizardIsContinuous(false);
                        datatype.parmWizardIsManual(NoYes::No);
                       datatype.parmWizardIsChangeDownAllowed(NoYes::No);
                       datatype.parmWizardIsChangeUpAllowed(NoYes::No);
                        datatype.parmSortField(1);                        
datatype.addParameterType(NumberSeqParameterType::DataArea, true, false);
                        this.create(datatype);
            }
}

[ExtensionOf(tableStr(CustParameters))]
final class CustParametersTest_Extension
{
    client server static NumberSequenceReference numRefTestId()
    {
        return NumberSeqReference::findReference(extendedTypeNum(TestId));
    }
}
Create a number sequence in a new module
·        Add a new element to the NumberSeqModule base enum.
·        Create a NumberSeqModule* class for our module.
·        To add a new element to the NumberSeqModule Base Enum we can use an extension.
·        Now we need to create a new class extends with NumberSeqApplicationModule
class NumberSeqModuleTest extends NumberSeqApplicationModule
{
    protected void loadModule()
    {
        NumberSeqDatatype datatype = NumberSeqDatatype::construct();
        datatype.parmDatatypeId(extendedTypeNum(TestId));
        datatype.parmReferenceHelp(literalStr('Test ID'));
        datatype.parmWizardIsContinuous(false);
        datatype.parmWizardIsManual(NoYes::No);
        datatype.parmWizardIsChangeDownAllowed(NoYes::No);
        datatype.parmWizardIsChangeUpAllowed(NoYes::No);
        datatype.parmSortField(1);       
        datatype.addParameterType(NumberSeqParameterType::DataArea, true, false);
        this.create(datatype);
    }

    public NumberSeqModule numberSeqModule()
    {
        return NumberSeqModule::Test;
    }

    [SubscribesTo(classstr(NumberSeqGlobal),delegatestr(NumberSeqGlobal, buildModulesMapDelegate))]
    static void buildModulesMapSubsciber(Map numberSeqModuleNamesMap)
    {
       NumberSeqGlobal::addModuleToMap(classnum(NumberSeqModuleTest), numberSeqModuleNamesMap);
    }
}

Job: (To load all module number sequences)
static void Test_NumSeqLoad(Args _args)
   {
      NumberSeqApplicationModule::loadAll();
   }  



Monday, May 21, 2018

Relax model restrictions to enable the refactoring of over-layering into extensions D365

//Relax model restrictions to enable the refactoring of over-layering into extensions

-> Temporarily allow over-layering in Microsoft models as needed to enable for compilation.
-> Locate the desired model within the C:\AOSService\PackagesLocalDirectory\<Package>\<Model> \Descriptor folder
-> Open the XML file & add below line. For example, DIMENSIONS.xml
<Customization>AllowAndWarn</Customization>
-> Refactor over-layering to extensions and test. Make use of extension capabilities
to eliminate over-layering. If needed, make extensibility requests.
-> Revert the temporary changes to Microsoft models.

Thursday, April 12, 2018

Hyperlinks for SSRS report in D365

Navigate report design->text box  properties-> Action

Example:1  - Single parameter filter
=Microsoft.Dynamics.Framework.Reports.BuiltInMethods.GenerateDrillThroughLink(
Parameters!AX_ReportContext.Value, 
Parameters!AX_UserContext.Value, 
"MenuItemName", 
"Display",  //Menu item type
"Table Name", 
"Field Name", "Field Value")

Example:2 - Multi-parameter Filter
=Microsoft.Dynamics.Framework.Reports.BuiltInMethods.GenerateDrillThroughLink(
Parameters!AX_ReportContext.Value, 
Parameters!AX_UserContext.Value, 
"MenuItemName", 
"Display", //Menu item type
"Table Name", 
"Field Name", "Field Value"
"Field Name", "Field Value")

Add this Method in your FORM. (where Menutiem denotes)

public boolean isRootNavigable()
{
return true;
}

Tuesday, April 3, 2018

MR Data Mart Schedule interval information through SQL query

//Get list of scheduled MR batch job

USE ManagementReporter

SELECT
Trig.Id,
Task.Name,
Trig.Interval,
   CASE Trig.[UnitOfMeasure]
   WHEN 1 THEN 'Seconds'
   WHEN 2 THEN 'Minutes'
   WHEN 3 THEN 'Hours'
   WHEN 4 THEN 'Days'
End as UnitOfMeasure

FROM [Connector].[Map] Map

Inner join [Scheduling].[Task] Task
               on Map.MapId = Task.Id
Inner join [Scheduling].[Trigger] Trig
               on Task.TriggerId = Trig.Id
ORDER BY Name desc


//Get Current Batch status of AX to MR integration data sync

USE ManagementReporter

SELECT T.NAME,
CASE TS.STATETYPE
      WHEN 3 THEN 'PROCESSING'
      WHEN 5 THEN 'COMPLETE'
      WHEN 7 THEN 'ERROR'
END AS STATETYPE,
TS.PROGRESS,
TS.LastRunTime as LastRun,
TS.NextRunTime as nextRun,
T.Id as TaskId,
T.TYPEID as TypeId,
T.ID AS TRIGGERID,
CASE TR.ISENABLED
      WHEN 1 THEN 'ENABLED'
      ELSE 'DISABLED'
END AS NAMESTATUS,
TR.INTERVAL,
CASE TR.UNITOFMEASURE
      WHEN 2 THEN 'MINUTES'
      ELSE 'SECONDS'
END AS INTERVALTIMING,
TS.STATETYPE
FROM SCHEDULING.TASK T JOIN SCHEDULING.TASKSTATE TS
ON T.ID = TS.TASKID JOIN SCHEDULING.[TRIGGER] TR ON TR.ID = T.TRIGGERID
WHERE ISENABLED <> 0
AND T.TYPEID in ('55D3F71A-2618-4EAE-9AA6-D48767B974D8',
'6F6B935B-FC0A-46B9-8F53-27C6AF7437F0',
'D81C1197-D486-4FB7-AF8C-078C110893A0')

ORDER BY T.NAME



//Get MR schedule error list

select
b.Name,
c.Text,
DATEADD(minute, DATEDIFF(minute,GETUTCDATE(),GETDATE()), a.StartTime) as LocalStartTime,
DATEADD(minute, DATEDIFF(minute,GETUTCDATE(),GETDATE()), a.EndTime) as LocalEndTime,
a.TotalRetryNumber,
a.IsFailed,
d.Name as TaskType
from [Scheduling].[Log] a
inner join [Scheduling].[Task] b on a.TaskId = b.Id
inner join [Scheduling].[Message] c on a.Id = c.LogId
inner join [Scheduling].[TaskType] d on b.TypeId = d.Id
where a.StartTime > (select DATEADD(DAY, -8, GETDATE()))
and c.Text like '%Error%'
order by LocalStartTime desc

Tuesday, March 20, 2018

AOS Service start Error

Error:
When you try to start the AOS. "Error 100: Cannot create another system semaphore"

Resolution:
Steps:
1. Add the below permission to AOS SQL user
    db_ddladmin, db_datareader, db_datawriter

2. Update the below query on SQL
    Query:
    update SQLSystemVariables set value = '4' where parm = 'SYSTIMEZONESVERSION'

Installation Error SQL server

Error:
An error occurred creating the configuration section handler for
userSettings/Microsoft.SqlServer.Configuration.LandingPage.Properties.Settings:
Could not load file or assembly 'System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'
or one of its dependencies. The system cannot find the file specified.

Resolution:
Open Cmd Prompt and below below cmd
rd /s /q %localappdata%\Microsoft_Corporation

Thursday, March 15, 2018

AutoNumberFormat options in D365

AutoNumberFormat options

These examples show how you can configure the AutoNumberFormat property to get different results:
AutoNumberFormat valueExample value
CAR-{SEQNUM:3}-{RANDSTRING:6}CAR-123-AB7LSF
CNR-{RANDSTRING:4}-{SEQNUM:4}CNR-WXYZ-1000
{SEQNUM:6}-#-{RANDSTRING:3}123456-#-R3V
KA-{SEQNUM:4}KA-0001
{SEQNUM:10}1234567890
QUO-{SEQNUM:3}#{RANDSTRING:3}#{RANDSTRING:5}QUO-123#ABC#PQ2ST
QUO-{SEQNUM:7}{RANDSTRING:5}QUO-0001000P9G3R
CAS-{SEQNUM:6}-{RANDSTRING:6}-{DATETIMEUTC:yyyyMMddhhmmss}CAS-002000-S1P0H0-20170913091544
CAS-{SEQNUM:6}-{DATETIMEUTC:yyyyMMddhh}-{RANDSTRING:6}CAS-002002-2017091309-HTZOUR
CAS-{SEQNUM:6}-{DATETIMEUTC:yyyyMM}-{RANDSTRING:6}-{DATETIMEUTC:hhmmss}CAS-002000-201709-Z8M2Z6-110901

CompileCIL and Refresh Services using X++

Ref: https://krishhdax.blogspot.in/2017/04/ax2012-compilecil-and-refresh-services.html 

static void CompileCILRefresh(Args _args)
{
    #AviFiles
    #File

    #define.fileName('AxTime.txt')

    TextIo                  file;
    FileIoPermission        permission;
    SysOperationProgress    progress;
    container               fileContainer;

    int                     i;

    Dialog                  dialog;

    DialogField             dlgCompile;
    DialogField             dlgCIL;
    DialogField             dlgIncCIL;
    DialogField             dlgRefreshService;

    int                     timeStarted[2];
    int                     timeAverage[4]; //1:FUllCompileTime,2:FULLCILCompileTime,3:IncrementalCILTime,4:RefreshServicesTime
    int                     timeExpected;

    Filename                filename
    ;

    void getAverageTime()
    {
        filename = WinAPI::getCurrentDirectory() + '\\' + fileName;

        permission = new FileIoPermission(filename, #io_read+#io_write);
        permission.assert();

        if(WinAPI::fileExists(filename))
        {
            file        = new TextIo(filename, #io_read);
            fileContainer   = file.read();
            timeAverage[1]  = str2int(conPeek(fileContainer,1));
            timeAverage[2]  = str2int(conPeek(fileContainer,2));
            timeAverage[3]  = str2int(conPeek(fileContainer,3));
            timeAverage[4]  = str2int(conPeek(fileContainer,4));
            file = null;
        }

        CodeAccessPermission::revertAssert();
    }

    void setAverageTime()
    {
        permission = new FileIoPermission(filename, #io_write);
        permission.assert();

        fileContainer = conNull();
        fileContainer = conIns(fileContainer,1,int2str(timeAverage[1]));
        fileContainer = conIns(fileContainer,2,int2str(timeAverage[2]));
        fileContainer = conIns(fileContainer,3,int2str(timeAverage[3]));
        fileContainer = conIns(fileContainer,4,int2str(timeAverage[4]));

        file = new TextIo(filename, #io_write);
        file.write(fileContainer);
        file.finalize();

        file = null;

        CodeAccessPermission::revertAssert();
        permission = null;
    }

    dialog  = new Dialog("Compile/CIl/Refresh");

    dialog.addInfoImage();
    dialog.addText("Please select actions needed and please be aware that all are time consuming processes");

    dialog.addGroup("Compile application");
    dlgCompile  = dialog.addFieldValue(extendedTypeStr(NoYesId),NoYes::No,"AOT Compile");

    dialog.addGroup("Compile CIL");
    dlgCIL      = dialog.addFieldValue(extendedTypeStr(NoYesId), NoYes::No, "FULL");
    dlgIncCIL   = dialog.addFieldValue(extendedTypeStr(NoYesId), NoYes::No, "Incemental");

    dialog.addGroup("Other");
    dlgRefreshService   = dialog.addFieldValue(extendedTypeStr(NoYesId),NoYes::No,"Refresh Services");

    if (!dialog.run())
        throw error("Operation aborted");

    filename        = #fileName;

    timeAverage[1]  = 3600; // 60:00 min
    timeAverage[2]  = 1800; // 30:00 min
    timeAverage[3]  = 900;  // 15:00 min
    timeAverage[4]  = 300;  // 5:00 min

    getAverageTime();

    timeExpected += dlgCompile.value()          ? timeAverage[1] : 0;
    timeExpected += dlgCIL.value()              ? timeAverage[2] : 0;
    timeExpected += dlgIncCIL.value()           ? timeAverage[3] : 0;
    timeExpected += dlgRefreshService.value()   ? timeAverage[4] : 0;

    progress = new SysOperationProgress();
    progress.updateInterval(0);
    progress.setAnimation(#AviStopwatch);

    progress.setTotal(1 + dlgCompile.value() + (dlgCIL.value() || dlgIncCIL.value()) + dlgRefreshService.value());

    timeStarted[1] = timeNow();

    info(strFmt("Process stared by %1",curUserId()));

    //Compile the application
    startLengthyOperation();
    sleep(3);

    //AOT Compile
    if (dlgCompile.value())
    {
        progress.incCount();
        progress.setText(strfmt("AOT Compile compiling | Start time : %1 ETA : %2",time2str(timeNow(),1,1),time2str(timeAverage[1] + timeNow(),1,1)));

        //Do function
        timeStarted[2] = timeNow();

        SysCompileAll::flushClient();
        SysCompileAll::compile();

        SysCheckList::finished(classnum(SysCheckListItem_Compile));
        SysCheckList::finished(classnum(SysCheckListItem_CompileUpgrade));
        SysCheckList::finished(className2Id(classStr(SysCheckListItem_CompileServ)));
        SysCheckList::finished(classnum(SysCheckListItem_SysUpdateCodeCompilInit));

        timeAverage[1] = ((timeNow()-timeStarted[2]) + timeAverage[1])/2;
        info(strFmt("AOT Compile toke : %1*",time2str(timeAverage[1],1,1)));
    }

    //Incremntal CIL
    if (dlgIncCIL.value())
    {
        progress.incCount();
        progress.setText(strfmt("Incremental CIL Compiling | Start time : %1 ETA : %2",time2str(timeNow(),1,1),time2str(timeAverage[3] + timeNow(),1,1)));

        //Do function
        timeStarted[2] = timeNow();
        SysCompileIL::generateIncrementalIL();

        timeAverage[3] = ((timeNow()-timeStarted[2]) + timeAverage[3])/2;
        info(strFmt("Increment CIL toke : %1*",time2str(timeAverage[3],1,1)));
    }
    //Full CIL
    else if (dlgCIL.value())
    {
        progress.incCount();
        progress.setText(strfmt("FULL CIL Compiling | Start time : %1 ETA : %2",time2str(timeNow(),1,1),time2str(timeAverage[2] + timeNow(),1,1)));

        //Do function
        timeStarted[2] = timeNow();
        SysCompileIL::generateIL();
        timeAverage[2] = ((timeNow()-timeStarted[2]) + timeAverage[2])/2;
        info(strFmt("FULL CIL toke : %1*",time2str(timeAverage[2],1,1)));
    }

    // Refresh services
    if (dlgRefreshService.value())
    {
        progress.setText(strfmt("Refresh Services | Start time : %1 ETA : %2",time2str(timeNow(),1,1),time2str(timeAverage[4] + timeNow(),1,1)));
        progress.incCount();

        timeStarted[2] = timeNow();

        AifServiceGenerationManager::registerServices();

        timeAverage[4] = ((timeNow()-timeStarted[2]) + timeAverage[4])/2;
        info(strFmt("Refresh Services toke : %1*",time2str(timeAverage[4],1,1)));
    }

    setAverageTime();

    endLengthyOperation();

    //Flush all
    sysFlushAOD::main(_args);
    sysFlushData::main(_args);
    sysFlushDictionary::main(_args);
    info(strFmt("*Averagetime"));
    info(strFmt("Total time spendt : %1",time2str(timeNow()-timeStarted[1],1,1)));
}

Resetting and Recalculating Tax amount for sales Order in DAX

//Resetting and Recalculating Tax amount for sales Order in DAX

static void San_Reset_RecalculateSalesTaxValue(Args _args)
{
    SalesTable                  salesTable;
    TaxRegulation            taxRegulation;
    SalesTotals                 salesTotals;
    SalesId                        salesId ="";
    ;
    salesTable = SalesTable::find(SalesId);
    if (salesTable)
    {
        salesTotals = SalesTotals::construct(salesTable, SalesUpdate::All);
        salesTotals.calc();
        taxRegulation = TaxRegulation::newTaxRegulation(salesTotals.tax(), null,salestable.TableId, salestable.RecId);
        if (taxRegulation.taxLinesExist())
        {
            taxRegulation.resetTaxRegulation();
            taxRegulation.saveTaxRegulation();
            info("Tax Amount resetted and recalculated for new lines");
        }
    }
}

Skip Inventory reservation on Sales order lines in D365FO

[ExtensionOf(classStr(InventUpd_Reservation))] final class InventUpd_ReservationCls_SAN_Extension {     void updateNow()     {         if(mo...