Friday, September 23, 2016

Redirect WMS page to Login Screen AX2012

Hi Guys,

We had a requirement with a client wherein they wanted to see the WMS login screen rather than the WMS Homepage to save that 1 extra click ;)

So to achieve this I had to make a small change in the "Index.aspx" file located at "C:\Program Files (x86)\Microsoft Dynamics AX\60\Warehouse Mobile Devices Portal\00\Views\Home".

The change was a small script to redirect the page:

<script type="text/javascript">
setTimeout('Redirect()',10);
function Redirect()
{
  location.href = 'http://wmsServerName:port/Execute/Display';
}
</script>

So this script will take you directly from 








To this screen:


Thursday, August 18, 2016

Create User from another user using X++ AX2012

While searching some issue I have a very interesting blog post about a utility which creates a new user based on an existing user. It copies the Roles and User Options from the existing user and creates a new one.

This utiltiy not limited to copy user roles but can copy User Groups and user Options too.



Some important methods of this utility are;

Create User lookup for FROM USER

public void fromUserLookup(FormStringControl userLookupControl)
{
    Query                   qry = new Query();
    QueryBuildDataSource    qbd;
    QueryBuildRange         qbr;
    SysTableLookup          sysTableLookup;
    Userinfo                userInfo;


    systablelookup = SysTableLookup::newParameters(tableNum(UserInfo), userLookupControl);
    SysTableLookup.addLookupfield(fieldNum(UserInfo, ID));
    SysTableLookup.addLookupfield(fieldNum(UserInfo, NetworkAlias));
    SysTableLookup.addLookupfield(fieldNum(UserInfo, Name));

    qbd = qry.addDataSource(tableNum(userInfo));
    qbd.addRange(fieldNum(UserInfo,Company)).value(curext());
    sysTableLookup.parmQuery(qry);
    sysTableLookup.performFormLookup();
}

Create User lookup for TO USER

public void toUserLookup(FormStringControl userLookupControl)
{
    Query                   qry = new Query();
    QueryBuildDataSource    qbd;
    QueryBuildRange         qbr;
    SysTableLookup          sysTableLookup;
    Userinfo                userInfo;


    systablelookup = SysTableLookup::newParameters(tableNum(UserInfo), userLookupControl);
    SysTableLookup.addLookupfield(fieldNum(UserInfo, ID));
    SysTableLookup.addLookupfield(fieldNum(UserInfo, NetworkAlias));
    SysTableLookup.addLookupfield(fieldNum(UserInfo, Name));

    qbd = qry.addDataSource(tableNum(userInfo));
    qbd.addRange(fieldNum(UserInfo,Company)).value(curext());
    qbr = qbd.addRange(fieldNum(UserInfo, Enable));
    qbr.value('1');
    sysTableLookup.parmQuery(qry);
    sysTableLookup.performFormLookup();
}

Function to copy USER ROLES

/// <summary>
/// copy roles assigned to one user to another
/// </summary>
/// <returns>
/// true; roles are copied across. false; roles failed to copied
/// </returns>
/// <remarks>
/// this method is used to copy user roles assigned to one user to another user.
/// </remarks>
private boolean copyUserRoles()
{
    boolean                 ret = true;

    SecurityRole            securityRole;

    SecurityUserRole        securityUserRole;
    SecurityUserRole        securityUserRoleExist;
    SecurityUserRole        securityUserRoleInsert;
    OMUserRoleOrganization  userRoleOrganization, userRoleOrganization_Insert;

    List                    copiedUserRoles = new List(Types::String);

    ListEnumerator          lEnumerator;

    setPrefix(strFmt("Copy user", fromUser, toUser));

    try
    {
        select securityRole where securityRole.AotName == 'SystemUser';
        delete_from securityUserRole where securityUserRole.User == toUser && securityUserRole.SecurityRole == securityRole.RecId;
   
        while select securityUserRole
                where securityUserRole.User == fromUser
            notExists join * from securityUserRoleExist
                where securityUserRoleExist.SecurityRole    == securityUserRole.SecurityRole
                    && securityUserRoleExist.User           == toUser
        {
            select securityRole where securityRole.RecId == securityUserRole.SecurityRole;

            copiedUserRoles.addStart(securityRole.Name);

            securityUserRoleInsert.initValue();
            securityUserRoleInsert.SecurityRole = securityUserRole.SecurityRole;
            securityUserRoleInsert.User         = toUser;
            securityUserRoleInsert.insert();
            securityUserRoleInsert.clear();

            while select userRoleOrganization
                    where userRoleOrganization.User == fromUser
                        && userRoleOrganization.SecurityRole == securityUserRole.SecurityRole
            {
                userRoleOrganization_Insert.initValue();

                userRoleOrganization_Insert.OMHierarchyType             = userRoleOrganization.OMHierarchyType;
                userRoleOrganization_Insert.OMInternalOrganization      = userRoleOrganization.OMInternalOrganization;
                userRoleOrganization_Insert.SecurityRole                = userRoleOrganization.SecurityRole;
                userRoleOrganization_Insert.SecurityRoleAssignmentRule  = userRoleOrganization.SecurityRoleAssignmentRule;
                userRoleOrganization_Insert.User                        = toUser;

                userRoleOrganization_Insert.insert();
                userRoleOrganization_Insert.clear();
            }
        }
    }
    catch
    {
        ret = false;
    }

    if (ret)
    {
        lEnumerator = copiedUserRoles.getEnumerator();

        if (copiedUserRoles.empty())
            info(strFmt("User %1 and %2 have already the same user role",fromUser, toUser));

        while (lEnumerator.moveNext())
        {
            info(strFmt('%1',lEnumerator.current()));
        }
    }
    else
        error(strFmt("User Roles aborted please review list"));

    return ret;
}

Function to copy USER OPTIONS
/// <summary>
/// copy options assigned to one user to another
/// </summary>
/// <returns>
/// true; options are copied across. false; options failed to copied
/// </returns>
/// <remarks>
/// this method is used to copy user's options assigned to one user to another user.
/// </remarks>
private boolean copyUserOptions()
{
    boolean                 ret = true;

    UserInfo                userInfoSource;
    UserInfo                userInfoTarget;

    SysUserInfo             sysUserInfoSource;
    SysUserInfo             sysUserInfoTarget;

    setPrefix(strFmt("Copy user options", fromUser, toUser));

    try
    {
        select userInfoSource
            where userInfoSource.id == fromUser
        join sysUserInfoSource
            where sysUserInfoSource.Id == userInfoSource.id;

        ttsBegin;
       
            select forUpdate userInfoTarget where userInfoTarget.id == toUser;
            userInfoTarget.filterByGridOnByDefault = userInfoSource.filterByGridOnByDefault;
            userInfoTarget.statuslineInfo = userInfoSource.statuslineInfo;
            userInfoTarget.update();

       
            select forUpdate sysUserInfoTarget where sysUserInfoTarget.Id == toUser;
            sysUserInfoTarget.DefaultCountryRegion = sysUserInfoSource.DefaultCountryRegion;
            sysUserInfoTarget.update();
        ttsCommit;

    }
    catch
    {
        ret = false;
    }

    if (ret)
    {
        info(strFmt("User %1 and %2 have already the same user options ", fromUser, toUser));
    }
    else
        error(strFmt("User Options aborted please review list "));

    return ret;
}

Function to copy USER GROUPS
/// <summary>
/// copy groups assigned to one user to another
/// </summary>
/// <returns>
/// true; groups are copied across. false; groups failed to copied
/// </returns>
/// <remarks>
/// this method is used to copy user groups assigned to one user to another user.
/// </remarks>
private boolean copyUserGroups()
{
    boolean                 ret = true;

    UserGroupList           userGroupList;
    UserGroupList           userGroupListExist;
    UserGroupList           userGroupListInsert;

    List                    copiedGroups = new List(Types::String);

    ListEnumerator          lEnumerator;

    setPrefix(strFmt("Copy user groups", fromUser, toUser));

    try
    {
        while select userGroupList
                where userGroupList.userId == fromUser
            notExists join * from userGroupListExist
                where userGroupListExist.groupId == userGroupList.groupId
                    && userGroupListExist.userId == toUser
        {
            copiedGroups.addStart(userGroupList.groupId);

            userGroupListInsert.initValue();
            userGroupListInsert.groupId = userGroupList.groupId;
            userGroupListInsert.userId  = toUser;
            userGroupListInsert.insert();
            userGroupListInsert.clear();
        }
    }
    catch
    {
        ret = false;
    }

    if (ret)
    {
        lEnumerator = copiedGroups.getEnumerator();

        if (copiedGroups.empty())
            info(strFmt("User %1 and %2 have already the same user Groups ",fromUser, toUser));

        while (lEnumerator.moveNext())
        {
            info(strFmt('%1',lEnumerator.current()));
        }
    }
    else
        error(strFmt("User Groups aborted please review list "));

    return ret;
}

Credit: http://daxture.blogspot.in/2015/01/assigning-security-roles-to-new-ax-user.html

Tuesday, August 16, 2016

Refresh AOD, Data and Dictionary using X++ AX2012

Using the below code you can refresh AOD, Dicitonary and Data:


static void refreshAll()
{
    #Aif
    SysSQMSettings  _sqmSettings;

    ttsBegin;
    update_recordSet _sqmSettings setting GlobalGUID = str2guid(#EmptyGuidString);
    ttsCommit;

    xSession::removeAOC();
    SysTreeNode::refreshAll();
    SysFlushSystemSequence::doFlush(); SysEvent::fireEvent(SysEventType::FlushSystemSequence);

    SysFlushDictionary::doFlush(); SysEvent::fireEvent(SysEventType::FlushDictionary);

    SysFlushDatabaseLogSetup::doFlush(curext()); SysEvent::fireEvent(SysEventType::FlushDatabaseLogSetup,0,[curext()]);
    SysFlushData::doFlush(); SysEvent::fireEvent(SysEventType::FlushData);
    SysFlushAOD::doFlush();
    SysEvent::fireEvent(SysEventType::FlushAOD);
    xSession::updateAOC();
}

Change menuitem property through X++ AX2012

In a new requirement, I had to generate a URL based on the logged-in user using a new parameters table. The URL had to be opened from EP->EmployeeServices and hence it is a URLMenuItem I was not able to handle it through URLRedirection in C#.

What I decided to change the URL property of the menuitem through code. Below is the code:

private void leaveURL(Str60 encryptedUserName)
{
    Name        encryptedName;
    TreeNode    objTreeNode;
    objTreeNode = TreeNode::findNode(@"\Web\Web Menu Items\URLs\ALE_ESSLeave\");

    if (objTreeNode)
    {
        objTreeNode.AOTsetProperties("PROPERTIES\n URL  #" + 'http://' + HcmSharedParameters::find().ALE_ESS_IP + '/oasis/AX_ESS_Integration.aspx?U=' + encryptedUserName +'&C=' + HcmSharedParameters::find().ALE_LeaveEncryptedCode + "\n ENDPROPERTIES\n");
        objTreeNode.AOTsave();
    }
}

Add/Remove Role to User through X++ code AX2012

Hi guys. We had a requirement where I had to provide SysAdmin role to the current user for the task which he is performing and once it is done then the role had to be removed. As ever google came to help big time and finally my code is ready:

Method to add role:

private void grantAdminRole()
{
    SecurityRole        role;
    SecurityUserRole    userRole;
    boolean             added;
    UserInfo            userInfo;

    select role where role.Name == 'System Administrator';

    select * from userRole
        where userRole.SecurityRole == role.RecId &&
            userRole.User == curUserId();

    if (!userRole || (userRole.AssignmentStatus != RoleAssignmentStatus::Enabled))
    {
        userRole.User = curUserId();
        userRole.SecurityRole = role.RecId;
        userRole.AssignmentMode = RoleAssignmentMode::Manual;
        userRole.AssignmentStatus = RoleAssignmentStatus::Enabled;
        SecuritySegregationOfDuties::assignUserToRole(userRole, null);
    }
}


Method to remove the role from user:

private void revokeAdminRole()
{
    fieldName                           userId;
    SysSecTreeRoles                     roleTree;
    SecurityUserRole                    securityUserRole;
    OMUserRoleOrganization              org;
    SecurityUserRoleCondition           condition;
    SecuritySegregationOfDutiesConflict conflict;
    SecurityRole                        role;

    ttsbegin;

    select role where role.Name == 'System Administrator';

    delete_from condition
        exists join securityUserRole
        where condition.SecurityUserRole == securityUserRole.RecId && securityUserRole.User == curUserId() && securityUserRole.SecurityRole == role.RecId;

    select OMInternalOrganization, SecurityRole from org where org.User == curUserId() && org.SecurityRole == role.RecId;

    if (org.SecurityRole)
    {
        EePersonalDataAccessLogging::logUserRoleChange(org.SecurityRole, org.omInternalOrganization, curUserId(), AddRemove::Remove);
    }

    delete_from org where org.User == curUserId() && org.SecurityRole == role.RecId;

    delete_from conflict where conflict.User == curUserId() && ((conflict.ExistingRole == role.RecId) || (conflict.NewRole == role.RecId));

    //<GEEEE>
    EePersonalDataAccessLogging::logUserRoleChange(role.RecId, 0, curUserId(), AddRemove::Remove);
    //</GEEEE>

    delete_from securityUserRole where securityUserRole.User == curUserId() && securityUserRole.SecurityRole == role.RecId;

    ttscommit;

}

Friday, July 8, 2016

Update ProductDimension, StorageDimension & SearchName of Items/Products

We had a requirement to update ProductDimension and StorageDimension of all the items. I wrote 2 jobs for the same. Below are those:

Update ProductDimension:
static void UpdateProductDimension(Args _args)
{
    EcoResProduct                       ecoResProduct;
    EcoResProductDimensionGroupProduct  ecoResProductDimensionGroupProduct;
 
    while select ecoResProduct
        where ecoResProduct.RecId != 0
    {
        ecoResProductDimensionGroupProduct.initFromProduct(ecoResProduct);
        ecoResProductDimensionGroupProduct.ProductDimensionGroup = 'NameHere';
        ecoResProductDimensionGroupProduct.insert();
    }
 
    info("Done");
}

Update StorageDimension:
static void Job48(Args _args)
{
    EcoResProduct                       ecoResProduct;
    EcoResStorageDimensionGroup         ecoResStorageDimensionGroup;
    EcoResStorageDimensionGroupProduct  ecoResStorageDimensionGroupProduct;
    EcoResStorageDimensionGroupItem     ecoResStorageDimensionGroupItem;
    InventTable                         inventTable;
 
    select Name from ecoResStorageDimensionGroup
        where ecoResStorageDimensionGroup.Name == 'NameHere';
 
    while select ecoResProduct
        join inventTable
        where ecoResProduct.RecId == inventTable.Product
    {
        ecoResStorageDimensionGroupItem.initValue();
        ecoResStorageDimensionGroupItem.ItemDataAreaId = inventTable.dataAreaId;
        ecoResStorageDimensionGroupItem.ItemId = inventTable.ItemId;
        ecoResStorageDimensionGroupItem.StorageDimensionGroup = ecoResStorageDimensionGroup.RecId;
        ecoResStorageDimensionGroupItem.insert();
    }
 
    info("Done");
}

Update SearchName:
static void Job48(Args _args)
{
    EcoResProductTranslation    ecoResProductTranslation;
    InventTable                 inventTable;
    EcoResProduct               ecoResProduct;
 
    update_recordset inventTable
    setting NameAlias = ecoResProductTranslation.Name
    join ecoResProduct
    where ecoResProduct.RecId == inventTable.Product
    join ecoResProductTranslation
    where ecoResProductTranslation.Product == ecoResProduct.RecId
    && ecoResProductTranslation.Name == 'Bentinck One Seater Sofa in Provincial Teak Finish with Mudramark';
 
    info("Done");
}

ReferenceSource: http://fandyax.blogspot.in/2013/04/how-to-using-x-create-item-in.html


Checklist can't be skipped Ax2012

Today I faced an issue where I had installed a Hotfix and completed the checklist but even after that the checklist kept popping up.

Then I came to know about the table which controls it. It's named "ReleaseUpdateConfiguration" and there is a field "MinorUpgrade" which will be checked. So in this case we need to uncheck it and the magic happens!

Source: http://yetanotherdynamicsaxblog.blogspot.in/2014/03/skip-modelstore-has-been-modified-dialog.html