Tuesday, November 24, 2020

Build model through command line

Reference: (source) -> https://www.theaxapta.com/2020/11/build-model-through-command-line.html 

Get List of all workspace

tf.exe workspaces /owner:* /computer:{Workspace} /collection:https://{TFS}.visualstudio.com

Delete a workspace

tf workspace /server:https://{TFS}.visualstudio.com/defaultcollection /delete "{Workspace};{Owner}"

You need to out email id of the owner, user id will not work.

compile model

C:\AosService\PackagesLocalDirectory\Bin\Xppc.exe -verbose -apixref -metadata=C:\AosService\PackagesLocalDirectory -modelmodule=<model_name> -referenceFolder=C:\AosService\PackagesLocalDirectory -xreffilename="C:\AosService\PackagesLocalDirectory\<model_name>\<model_name>.xref" -refPath=C:\AosService\PackagesLocalDirectory\<model_name>\bin -output=C:\AosService\PackagesLocalDirectory\<model_name>\bin -log=C:\<log_path>\Dynamics.AX.<model_name>.xppc.log -xmllog=C:\<log_path>\Dynamics.AX.<model_name>.xppc.xml

compile model best practices

C:\AosService\PackagesLocalDirectory\Bin\xppbp.exe -metadata=C:\AosService\PackagesLocalDirectory -packagesRoot=C:\AosService\PackagesLocalDirectory -module=<model_name> -model=<model_name> -all -log=C:\<log_path>\Dynamics.AX.<model_name>.xppbp.log -xmllog=C:\<log_path>\Dynamics.AX.<model_name>.xppbp.xml

compile labels

C:\AosService\PackagesLocalDirectory\Bin\LabelC.exe -metadata=C:\AosService\PackagesLocalDirectory -modelmodule=<model_name> -output=C:\AosService\PackagesLocalDirectory\<model_name>\Resources\ -outlog=C:\<log_path>\Dynamics.AX.<model_name>.labelc.log -errlog=C:\<log_path>\Dynamics.AX.<model_name>.labelc.err

compile reports

C:\AosService\PackagesLocalDirectory\Bin\ReportsC.exe -metadata=C:\AosService\PackagesLocalDirectory -modelmodule=<model_name> -LabelsPath=C:\AosService\PackagesLocalDirectory -output=C:\AosService\PackagesLocalDirectory\<model_name>\Reports\ -log=C:\<log_path>\Dynamics.AX.<model_name>.reportsc.log -xmllog=C:\<log_path>\Dynamics.AX.<model_name>.reportsc.xml

sync db

C:\AosService\PackagesLocalDirectory\Bin\SyncEngine.exe -syncmode=fullall -metadatabinaries=C:\AosService\PackagesLocalDirectory -connect="Data Source=ERP-BL-D-APP-1;Initial Catalog=AxDB;Integrated Security=True;Enlist=True;Application Name=SyncEngine" -fallbacktonative=False -raiseDataEntityViewSyncNotification

Monday, November 23, 2020

Reserve and Unreserve Sales order line X++ D365FO

Code for reserve and unreserved  sales order lines

Inputs: SalesLine, InventDim (Combination to reserve), Qty

Note

To Reserve -> Pass Qty as negative

To Unreserved -> Pass Qty as positive

Code:

InventMovement         movement;

movement = inventTrans::findTransId(_salesLine.InventTransId).inventMovement(true); 

InventUpd_Reservation   reservation;

 reservation  = InventUpd_Reservation::newInventDim(movement, _inventDim, _qty, false);

reservation.updateNow();

PO Registration X++ D365FO

Code to do registration through X++

Note: To do reverse registration provide input qty as Negative, otherwise to add new registration then qty must be positive.

private void inventTransactionRegister( InventTransId    _inventTransId, 

                                            Qty     _qty, 

                                            InventBatchSerialId   _batchNo = '', 

                                            InventBatchSerialId   _serialNo = '') 

    {

        InventTransWMS_Register     inventTransWMS_register;

        TmpInventTransWMS           tmpInventTransWMS;

        InventDim                   inventDim;

        InventTrans                 inventTrans = InventTrans::findTransId(_inventTransId);

        boolean                     ret;

        //inventTransWMS_register = inventTransWMS_register::newStandard(tmpInventTransWMS);

        inventDim               = inventTrans.inventDim();


        InventSerial    inventSerial;

        InventBatch     inventBatch;


        tmpInventTransWMS.clear();

        tmpInventTransWMS.ItemId = inventTrans.ItemId;

        tmpInventTransWMS.initFromInventTrans(inventTrans);

        tmpInventTransWMS.InventQty   = _qty;

        if(_batchNo && 

                this.checkTrackingDimensionEnabledItem(inventTrans.ItemId, fieldNum(InventDim, InventBatchId)))

        {

            inventBatch = InventBatch::findOrCreate(_batchNo, inventTrans.ItemId);

            inventDim.inventBatchId = inventBatch.inventBatchId;

        }

        if(_serialNo && 

                this.checkTrackingDimensionEnabledItem(inventTrans.ItemId, fieldNum(InventDim, InventSerialId)))

        {

            inventSerial = InventSerial::findOrCreate(_serialNo, inventTrans.ItemId);

            inventDim.inventSerialId = inventSerial.InventSerialId;

        }

        tmpInventTransWMS.InventDimId = inventDim::findOrCreate(inventDim).inventDimId;

        tmpInventTransWMS.insert();

inventTransWMS_register = inventTransWMS_register::newStandard(tmpInventTransWMS);

        ret = inventTransWMS_register.writeTmpInventTransWMS(tmpInventTransWMS,

                                                        inventTrans,

                                                        inventTrans.inventDim());

        if(ret)

        {

            inventTransWMS_register.updateInvent(inventTrans);

        }


}

Tuesday, August 18, 2020

Solution for BP: BP RULE -> BPUpgradeCodeLateBoundCall

 

BP:

BPUpgradeCodeLateBoundCall: BP Rule: [BPUpgradeCodeLateBoundCall]:A late bound call callingForm.refresh is made. In source system (AX 2012) it is possible to dynamically call methods where the number and type of the parameters does not match with the method definition. This is not supported in AX 7, where the number and types of parameters have to match. Even if the parameters do match, the late bound call is extremely expensive. Mitigation: Use a class or interface hierarchy to provide a type safe fast call, or use the IS and AS operators to cast to a known type before calling.

Calling form method in another FORM>

Solution:

1. Interface class ( new class for form)

   interface MyCustomFormInterface
 {
    public void refresh() // in my case method name is refresh
{
}
}

2. Go to Form -> MyCustomForm

   In declaration, add implements MyCustomFormInterface

3. In caller form

//get callerFormRun

MyCustomFormInterface frInterface = callerFormRun as MyCustomFormInterface

if(frInterface)

{

frInterface.refresh();

}

Wednesday, August 12, 2020

Fetch Product/Storage/Tracking dimension enabled or disabled based on itemId

 InventTable     inventTable;

   InventDimParm   inventDimParm;

   inventTable   = InventTable::find('A0001');

   inventDimParm =  InventDimParm::activeDimFlag(InventDimGroupSetup::newInventTable(inventTable));

   if(inventDimParm.InventLocationIdFlag)

   {

       info("warehouse is Enabled");

   }

Tuesday, July 21, 2020

Grid Row coloring in D365FO

[ExtensionOf(formdatasourcestr(SalesTable, SalesLine))]
Final class SONSalesTableDisplayOption_Extension
{
    public void displayOption(Common _record, FormRowDisplayOption _options)
    {
        InventDimCtrl_Frm_Mov inventDimFormSetup;
        InventDimControlsCollect inventDimControls;
        InventDimFormControlInterface fc;
        SalesLine salesLineLocal =  _record;
        #define.White(255, 255, 255)

        FormDataSource SalesLine_ds = this;
        FormRun formRun = SalesLine_ds.formRun();
        inventDimFormSetup = formRun.inventDimSetupObject();
        FormRealControl SalesLine_SalesQty = formRun.design(0).controlName("SalesLine_SalesQty");

        next displayOption(_record, _options);

        if (saleslineLocal.SalesQty != salesLineLocal.songetInvQty())
                {
                    _options.backColor(WinAPI::RGB2int(255,0,0));

//_options.textColor(WinAPI::RGB2int(#White)); invert color text
        
                    //Mark coloring by inventory dimension
                    inventDimControls = inventDimFormSetup.inventDimControls();
                    for (fc = inventDimControls.first(); fc; fc = inventDimControls.next())
                    {
                        if (fc.visible() && fc.isInGrid())
                                _options.affectedElementsByControl(fc.controlObject().id());
                    }
        
                    _options.affectedElementsByControl(SalesLine_SalesQty.id());
                }
    }

}

Tuesday, May 12, 2020

Get List of Model Metadata objects X++ D365FO

class GetListOfMetdataObjectByModelName
{
    /// <summary>
    /// Runs the class with the specified arguments.
    /// </summary>
    /// <param name = "_args">The specified arguments.</param>
    public static void main(Args _args)
    {
        Microsoft.Dynamics.AX.Metadata.Storage.MetadataProviderFactory metadataProviderFactory =
            new Microsoft.Dynamics.AX.Metadata.Storage.MetadataProviderFactory();
        var environment = Microsoft.Dynamics.ApplicationPlatform.Environment.EnvironmentFactory::GetApplicationEnvironment();
        str packageDir = environment.get_Aos().get_PackageDirectory();
        Microsoft.Dynamics.AX.Metadata.Storage.DiskProvider.DiskProviderConfiguration diskProviderConfiguration =
            new Microsoft.Dynamics.AX.Metadata.Storage.DiskProvider.DiskProviderConfiguration();
        diskProviderConfiguration.AddMetadataPath(packageDir);
        Microsoft.Dynamics.AX.Metadata.Providers.IMetadataProvider provider =
            metadataProviderFactory.CreateDiskProvider(diskProviderConfiguration);

        str modelName = 'DEVTESTMODEL';

        //Code is to extract is For TableExtensions

        //Change code - Provider.Table
        var TableExtensions = provider.TableExtensions.ListObjectsWithModificationInfo(modelName);
        var TableExtensionsEnumerator = TableExtensions.getEnumerator();
        while(TableExtensionsEnumerator.moveNext())
        {
            var curVal = TableExtensionsEnumerator.get_current();
            var metadataName = strRem(subStr(curVal.ToString(), 2, strFind(curVal.ToString(), ",", 1, strLen(curVal.ToString()))), ",");
            info(strFmt("%1 - TableExtensions - %2",modelName, metadataName));
        }
    }

}

Get Model list with versions & Application & Platform Version X++ D365FO

class GetModelListCls
{
    /// <summary>
    /// Runs the class with the specified arguments.
    /// </summary>
    /// <param name = "_args">The specified arguments.</param>
    public static void main(Args _args)
    {
        str60                   moduleName;
        CLRObject               moduleModels, sanModels;
        CLRObject               modelEnumerator, sanEnumerator;
        str60                   moduleVersion;

        Microsoft.Dynamics.AX.Metadata.MetaModel.ModelInfo modelInfo;

        moduleModels = Microsoft.Dynamics.Ax.Xpp.MetadataSupport::GetInstalledModuleNames();
        modelEnumerator = moduleModels.GetEnumerator();
        
        while (modelEnumerator.moveNext())
        {
            moduleName = modelEnumerator.get_Current();
            sanModels = Microsoft.Dynamics.Ax.Xpp.MetadataSupport::GetModelsInModuleSortedByDisplayName(moduleName);
            sanEnumerator = sanModels.GetEnumerator();
            sanEnumerator.MoveNext();
            modelInfo = sanEnumerator.get_Current();

            moduleVersion = strfmt("%1.%2.%3.%4",
                                        modelInfo.VersionMajor,
                                        modelInfo.VersionMinor,
                                        modelInfo.VersionBuild,
                                        modelInfo.VersionRevision);
            // modelInfo.Layer // Filter based on layers - ISV layer 8
            info(strFmt("%1 - %2 - %3",modelInfo.Module, moduleVersion,modelInfo.Publisher));
        }

        Microsoft.Dynamics.BusinessPlatform.ProductInformation.Provider.ProductInfoProvider provider = Microsoft.Dynamics.BusinessPlatform.ProductInformation.Provider.ProductInfoProvider::get_Provider();
        info(strFmt("Application version: %1",provider.ApplicationVersion));
        info(strFmt("Platform version: %1  ( %2 )",provider.ApplicationVersion,provider.get_PlatformBuildVersion()));
    }

}

Monday, January 27, 2020

Alert notification pop up and In user message center for custom/standard table in D365FO



///  class delivers the alerts notifications to user for custom tables
class BRUEventNotification_Test extends EventNotification
{
    SysIMailerNonInteractive mailer;
    Email        senderEmailAddress;

    public EventInboxId create()
    {
        SysUserInfo     userInfo;

        super();

        // send mail as well if enabled.
        userInfo = SysUserInfo::find(inbox.UserId);
        if (userInfo && userInfo.EventWorkflowTasksInEmail)
        {
            if (SysEmailDistributor::validateEmail(userInfo.emailDisplay()))
            {
                inbox.SendEmail = true;
                inbox.EmailRecipient = userInfo.emailDisplay();
                this.sendMail();
            }
        }

        inbox.AlertCreatedDateTime = DateTimeUtil::newDateTime(DateTimeUtil::getSystemDate(DateTimeUtil::getUserPreferredTimeZone()),DateTimeUtil::getTimeNow(DateTimeUtil::getUserPreferredTimeZone()),DateTimeUtil::getUserPreferredTimeZone());
        inbox.update();
        this.addPopupNotification(inbox, SysUserInfo::find(inbox.userId).EventPollFrequency, 30,this.ParmMenuFunction().name(),MenuItemType::Display,this.ParmRecord().RecId);//To get alert in to message center
        return inbox.InboxId;
    }

    private void addPopupNotification(EventInbox _inbox, int _reminderInterval, int _addDays, MenuItemName _menuItemName, MenuItemType _menuItemType, Int64 _recId)
    {
        SystemNotificationDataContract ndc = new SystemNotificationDataContract();
        Array actions = new Array (Types::Class);
        Array userList = new Array(Types::String);

        // create the message to be displayed in the message center
        userList.value(1, _inbox.UserId);

        ndc.Message(_inbox.Message);
        ndc.Title(_inbox.Subject);
        ndc.RuleId(_inbox.RuleId);
        ndc.Type(SystemNotificationType::Alert);
        ndc.State(SystemNotificationState::Active);
        ndc.Severity(SystemNotificationSeverity::Informational);
        ndc.Users(userList);
        ndc.ReminderInterval(_reminderInterval);
        ndc.ExpirationDateTime(DateTimeUtil::addDays(DateTimeUtil::utcNow(), _addDays));

        if (_menuItemName)
        {
            // create the hyperlink to the form
            SystemNotificationActionDataContract adc = new SystemNotificationActionDataContract();
            userList.value(1, _inbox.UserId);
            adc.Message(_inbox.AlertedFor);
            if (_menuItemType == MenuItemType::Action)
            {
                adc.Type(SystemNotificationActionType::AxActionMenuFunction);
            }
            else
            {
                // if it isn't an action menu item, assume display
                adc.Type(SystemNotificationActionType::AxDisplayMenuFunction);
            }

            SystemNotificationMenuFunctionDataContract notificationActionData = new SystemNotificationMenuFunctionDataContract();
            notificationActionData.MenuItemName(_menuItemName);
            notificationActionData.Data(int642Str(_recId));
            adc.Data(FormJsonSerializer::serializeClass(notificationActionData));
            actions.value(1,adc);
            ndc.Actions(actions);
        }

        // add to the Message center
        SystemNotificationsManager::AddNotification(ndc);
    }

    protected void new()
    {
        super();
        inbox.NotificationSource = EventNotificationSource::Alerts;
    }

    protected Email senderEmailAddress()
    {
        SysUserInfo     sysUserInfo;

        if (! senderEmailAddress)
        {
            // get the sender email address
            sysUserInfo = SysUserInfo::find(curuserid());
            senderEmailAddress = sysUserInfo.emailDisplay();

            // set senderEmail = toEmail
            if (! senderEmailAddress)
            {
                sysUserInfo         = SysUserInfo::find(inbox.UserId);
                senderEmailAddress  = sysUserInfo.emailDisplay();
            }
        }

        return senderEmailAddress;
    }

    protected void sendMail()
    {
        #define.mailPriority(1)

        super();

        if (mailer == null)
        {
            mailer = SysMailerFactory::getNonInteractiveMailer();
        }

        if (mailer != null
            && SysEmailDistributor::validateEmail(this.senderEmailAddress()))
        {
            try
            {
                var messageBuilder = new SysMailerMessageBuilder();
                messageBuilder.setFrom(this.senderEmailAddress(), "@SYS115063")
                              .setSubject(inbox.Subject)
                              .addTo(inbox.EmailRecipient)
                              .setPriority(#mailPriority)
                              .setBody(strReplace(inbox.Message, '\r\n', '<br>'));
                mailer.sendNonInteractive(messageBuilder.getMessage());
            }
            catch
            {
                warning(strfmt("@SYS324464",inbox.EmailRecipient));
                mailer = null;
            }
        }
    }

    protected static BRUEventNotification_Test construct()
    {
        return new BRUEventNotification_Test();
    }

    public static BRUEventNotification_Test newStandard(
        userId                  _userId,
        EventSubject            _subject,
        EventMessage            _message,
        EventNotificationType   _eventNotificationType,
        Common                  _record)
    {
        BRUEventNotification_Test  notification = BRUEventNotification_Test::construct();
        MenuFunction    getmenuFunction;
        getmenuFunction = new MenuFunction(menuitemdisplaystr(TestTableDetails),MenuItemType::Display);
        notification.parmUserId(_userId);
        notification.parmSubject(_subject);
        notification.parmMessage(_message);
        notification.parmNotificationType(_eventNotificationType);
        notification.parmRecord(_record);
        notification.parmDataSourceName(tableId2Name(tableNum(TestTable)));
        notification.parmMenuFunction(getmenuFunction);

        return notification;
    }

}

Convert Call stack to readable format in D365FO X++

//Input --container _xppCallStack = xSession::xppCallStack();  Public static str POL_formatXppCallStack(container _xppCallStack, int _skipFr...