Sunday, June 30, 2013

Customize Caller Args

From the caller:
    Args args;
    Object formRun;
    args = new Args();
    args.name(formStr(BudgetModelLookup));
    args.caller(_ctrl);
    formRun = classfactory.formRunClass(args);
    formRun.init();
    _ctrl.performFormLookup(formRun);

With the pre-built form BudgetModelLookup
the caller's formRun.init() invokes callee's init method, as the callee is a form itself.
 public void init()
{
    FormStringControl callingControl;
    callingControl = SysTableLookup::getCallerStringControl(
        this.args());
    super();
    budgetModelTree = BudgetModelTree::construct(
        ModelTree,
        callingControl.text());
    budgetModelTree.buildTree();
}
The callee contruct and build the UI. After the callee's init, the process flow goes back to the caller's code, which performs lookup
 _ctrl.performFormLookup(formRun);

Saturday, June 29, 2013

NonExist Join

static void Job7(Args _args)
{
    container ret;
    container data;
    CustTable custTable;
    InventBuyerGroupList groupList;
    InventBuyerGroup inventBuyerGroup;
    while select custTable
        notExists join firstOnly groupList
        where groupList.CustAccount == custTable.AccountNum
        join inventBuyerGroup
        where
         groupList.GroupId == InventBuyerGroup.Group
    {
       
        data = [custTable.AccountNum,
        custTable.AccountNum,
        custTable.name()];
        ret = conIns(ret, conLen(ret)+1, data);      
    }
}

select custTable
        notExists join firstOnly groupList
        where groupList.CustAccount == custTable.AccountNum
select all customers whose account number does not exist in GroupList(InventBuyerGroupList ).

Friday, June 28, 2013

Create Seq Handler

Methods to be added on the datasource (override)

Form method
public NumberSeqFormHandler numberSeqFormHandler() { if (!numberSeqFormHandler) { numberSeqFormHandler = NumberSeqFormHandler::newForm( CustParameters::numRefCustGroupId().NumberSequenceId, element, CustGroup_ds, fieldNum(CustGroup,CustGroup)); } return numberSeqFormHandler; } Override Datasource
public void create(boolean _append = false) { element.numberSeqFormHandler().formMethodDatasourceCreatePre(); super(_append); element.numberSeqFormHandler().formMethodDatasourceCreate(); }
public void delete() { ttsBegin; element.numberSeqFormHandler().formMethodDatasourceDelete(); super(); ttsCommit; }
public void write() { ttsBegin; super(); element.numberSeqFormHandler().formMethodDatasourceWrite(); ttsCommit; }
public boolean validateWrite() { boolean ret; ret = super(); ret = element.numberSeqFormHandler().formMethodDatasourceValidateWrite(ret) && ret; return ret; }
public void linkActive() { element.numberSeqFormHandler().formMethodDatasourceLinkActive(); super(); }
override form method public void close() { if (numberSeqFormHandler) { numberSeqFormHandler.formMethodClose(); } super(); }

Generate Number Seq

User CustGroupId as an example,
add code to class: NumberSeqModuleCustomer
    datatype.parmDatatypeId(extendedTypeNum(CustGroupId));
    datatype.parmReferenceHelp("Customer group ID");
    datatype.parmWizardIsContinuous(false);
    datatype.parmWizardIsManual(NoYes::No);
    datatype.parmWizardIsChangeDownAllowed(NoYes::Yes);
    datatype.parmWizardIsChangeUpAllowed(NoYes::Yes);
    datatype.parmWizardHighest(999);
    datatype.parmSortField(20);
    datatype.addParameterType(NumberSeqParameterType::DataArea, true, false);
    this.create(datatype);

Locate Table: CustParameters, add a new method to this table.
public server static NumberSequenceReference numRefCustGroupId()
{
    return NumberSeqReference::findReference(
    extendedTypeNum(CustGroupId));
}
To Test the sequence generated, create a job as the following:
static void number(Args _args)
{
    NumberSeq  numberSeq;
    CarId num;
    ;
    numberSeq = NumberSeq::newGetNum(CustParameters::numRefCustGroupId());
    num = numberSeq.num();
    info(num);
}
 

Wednesday, June 26, 2013

LinkType

The LinkType property determines how two data sources
are joined. The following list describes each option:
• Passive: The query on the joined data source is only
executed when the form is opened. A later change in the
controlling data source does not change the view.
• Delayed: The query on the joined data source is
executed every time that the controlling data source is
changed. The query execution is delayed to avoid the
fetch of data, if the controlling data source is changed
multiple times in a short time. This is the case when the
user is scrolling through data on a grid.
• Active: This option is similar to Delayed, except there is
no delay before the query is executed.
• InnerJoin: Selects records from the main table that have
matching records in the joined table and vice versa. If
the joined table does not have any records related to the
main table record, the main table record is not
displayed. Each match returns a result set of the main
table record and joined table record joined together as
one record. This is useful when wanting to display
records from both tables in a grid.
• OuterJoin: Selects records from the main table whether
they have matching records in the joined table. Each
match returns a result set of the main table record and
joined table record joined together as one record. If
there is no match, the fields from the joined table will be
empty.
• ExistsJoin: Selects a record from the main table only if
there is a matching record in the joined table. As soon as
a matching record is found, the main table record is
returned. The record in the joined table is never
retrieved.
• NotExistsJoin: Select records from the main table that
do not have a match in the joined table.

Tuesday, June 25, 2013

Map

    Map mapStateNumbers;
    MapEnumerator enumerator;
    CustTable custTable;
    mapStateNumbers = new Map(Types::String, Types::Integer);
    while select custTable
    {
        if(mapStateNumbers.exists(custTable.stateName()))
        {
        mapStateNumbers.insert(custTable.stateName(), mapStateNumbers.lookup(custTable.stateName())+1);
        }
        else
        {
        mapStateNumbers.insert(custTable.StateName(), 1);
        }
    }
    enumerator = mapStateNumbers.getEnumerator();
    while (enumerator.moveNext())
    {
        info(strfmt("%1 customers are located in %2.", enumerator.currentValue(), enumerator.currentKey()));
    }

Write a text file

    FileName fileName = 'c:\\test.txt';
    FileIoPermission permission;
    FileIO fileIO;
    str outputText;
    #File
    ;
    permission= new FileIoPermission(filename,#io_write);
    permission.assert();
    fileIO= new FileIO(filename, #io_write);
    if (fileIO)
    {
        outputText = "text that will go into the text file.";
        fileIO.write(outputText); //write the text to the file.
        fileIO.finalize(); //finish the file.
    }

Monday, June 24, 2013

Activities and SubActivities

Table HierarchyTreeTable and smmActivities contain activities and subactivities data.
In class HierarchTreeTable, method insertNode and insertRoot called from Form Hierarchy:write(), here is the node insertion:

ttsbegin;
        hierarchyTreeTable.clear();
        hierarchyTreeTable.HierarchyId = _hierarchyId;
        hierarchyTreeTable.ElementNumber = NumberSeq::newGetNum(CompanyInfo::numRefElementNumber()).num();
        hierarchyTreeTable.SiblingNumber = HierarchyTreeTable::nextSiblingNum(_hierarchyId, _parentElementNumber);
        hierarchyTreeTable.ParentElementNumber = _parentElementNumber;
        hierarchyTreeTable.ElementNodeType = ElementNodeType::Node;
        hierarchyTreeTable.Name = strLTrim(_name);
        hierarchyTreeTable.Path = HierarchyTreeTable::findElementNumber(_hierarchyId, _parentElementNumber).Path + hierarchyTreeTable.ParentElementNumber + #sharp;
        hierarchy=Hierarchy::find(_hierarchyId);
        smmActivities.clear();
        smmActivities.setActivityNum();
        smmActivities.Purpose =hierarchyTreeTable.Name;
        smmActivities.IsTemplate =hierarchy.IsTemplate;
        if (Hierarchy::isHierarchyTypeCRM(hierarchy.HierarchyType))
        {
            common = HierarchyLinkTable::findAssociation(hierarchyTreeTable.HierarchyId, Hierarchy::hierarchyType2tableId(hierarchy.HierarchyType));
            smmActivities.initFromCommon(common);
        }
        smmActivities.insert();
        hierarchyTreeTable.RefRecId = smmActivities.RecId;
        hierarchyTreeTable.insert();
        ttscommit;

Root Insertion:
  ttsbegin;
        hierarchyTreeTable.clear();
        hierarchyTreeTable.HierarchyId = _hierarchyId;
        hierarchyTreeTable.ElementNumber = NumberSeq::newGetNum(CompanyInfo::numRefElementNumber()).num();
        hierarchyTreeTable.SiblingNumber = 0;
        hierarchyTreeTable.ElementNodeType = ElementNodeType::Node;
        hierarchyTreeTable.Name = strLTrim(_name);
        if (isConfigurationkeyEnabled(configurationKeyNum(Project3)))
        {
            hierarchyTreeTable.psaLevelName = strLTrim(_name);
            hierarchyTreeTable.psaLevelDescription = ProjTable::find(strLTrim(_name)).Name;
            hierarchyTreeTable.psaNameLink = strLTrim(_name);
            hierarchyTreeTable.psaHierarchyLevelType = PSAHierarchyLevelType::Root;
        }
        hierarchyTreeTable.insert();
        ttscommit;

Thursday, June 13, 2013

Find a field -- ProfessionalTitle

select * from syscolumns A inner join sysobjects B
on A.id = B.id
where A.name = 'professionaltitle'

select professionaltitle,* from DMFEMPLOYEEENTITY where professionaltitle <> ''
select professionaltitle, * from dirpartytable where professionaltitle <> ''

AX Reference Sources

AX Server Team Blog:
http://blogs.msdn.com/b/daxserver/archive/2013/05.aspx
 
AX Support Blog:
http://blogs.msdn.com/b/axsupport/
 
AX Demo/Sample Solution Site:
https://mbs.microsoft.com/Cms/Templates/document/General.aspx?NRMODE=Published&NRNODEGUID=%7bACA31BB9-CB57-4B7F-A948-880FAEF28099%7d&NRORIGINALURL=%2fpartnersource%2fdeployment%2fmethodology%2fvpc%2fAX2012DemoToolsMaterials&NRCACHEHINT=Guest
 
AX UK Blog
http://blogs.msdn.com/b/ukax/
 
AX Business Intelligence
http://blogs.msdn.com/b/dynamicsaxbi/
 
http://blogs.msdn.com/b/saveenr/
 
http://blogs.msdn.com/b/mfp/

Table Permissions Framework

Set up TPF: http://msdn.microsoft.com/en-us/subscriptions/hh965683.aspx
Set up Record level permission: http://blogs.msdn.com/b/daxserver/archive/2013/05/13/enabling-field-level-authorization-in-ax-2012.aspx

Join 2 Tables

    Address addressTable2;
    AddressState addressStateTable3;
    struct sut4;
    ;
    sut4 = new struct("str StateName; str StateId; str Phone");

    while select *
        from addressTable2
            order by addressStateTable3 .Name
                , addressTable2 .Phone
        join addressStateTable3
            where addressTable2 .State ==
                addressStateTable3 .StateId
                && addressTable2 .State LIKE "N*"
    {
        sut4.value("StateName", addressStateTable3 .Name );
        sut4.value("StateId", addressStateTable3 .StateId );
        sut4.value("Phone", addressTable2 .Phone );

        info(sut4.toString());
    }

Group and Order
static void SelectGroupBy6Job(Args _args)
{
    Address tabAddress;
    AddressState tabAddressState;
    ;
    info("Start of job.");

    WHILE SELECT
        count(RecId)
        from tabAddress
        join tabAddressState
            GROUP BY
                tabAddress .State
                ,tabAddressState .Name
            ORDER BY tabAddress .State desc
            where
                tabAddress .State like "*N*"
                && tabAddressState .StateId == tabAddress .State
    {
        info(strFmt
            ("%1 = Count , StateId = %2 , StateName = %3"
            ,tabAddress .RecId ,tabAddress .State
            ,tabAddressState .Name
            ));
    }
    info("End of job.");
}

Tuesday, June 11, 2013

label files

C:\Program Files\Microsoft Dynamics AX\60\Server\MicrosoftDynamicsAX\bin\Application\Appl\Standard
AxSysen-us.ald

Sunday, June 9, 2013

select for update

static void UpdateOrg(Args _args)
{
Organization tstOrg;
ttsBegin;
while select forupdate * from tstOrg
{
tstOrg.State = "IL";
tstOrg.NumberOfEmployees = tstOrg.NumberOfEmployees+10;
tstOrg.update();
}
ttsCommit;
}

Friday, June 7, 2013

Call WebService from AX

Create class library project in VS, add services references, add to AOT, and deploy the project to both AX server and client.
In AX, add code some reference code.

VERAxServicesNameServcies.AxCustomerSvc.CustomerClient customerClient;
    VERAxServicesNameServcies.AxCustomerSvc.ICustomer customer;
    System.Exception Exception;
     System.ServiceModel.Description.ServiceEndpoint endPoint;
    System.ServiceModel.EndpointAddress endPointAddress;
    System.Type type;
    ;
    try
    {
        // Create a service client proxy
        type= CLRInterop::getType('VERAxServicesNameServcies.AxCustomerSvc.CustomerClient');
        customerClient = AifUtil::createServiceClient(type);
          // Create and endpoint address, This should be a parameter stored in the system
        endPointAddress = new System.ServiceModel.EndpointAddress("http://10.242.25.20:8081/Customer.svc");
        // Get the WCF endpoint
        endPoint = customerClient.get_Endpoint();
        // Set the endpoint address.
        endPoint.set_Address(endPointAddress);
        // Use the zipcode to find a place name
        //customer= customerClient.GetCustomer(1);
        // Use the getAnyTypeForObject to marshal the System.String to an
        //Ax anyType
        // so that it can be used with info()
        info(strFmt('%1', CLRInterop::getAnyTypeForObject(customerClient.GetCustomerTest(1))));
    }
    catch
    {
        // Get the .NET Type Exception
        exception = CLRInterop::getLastException();
        // Go through the inner exceptions
        while(exception)
        {
            // Print the exception to the infolog
            info(CLRInterop::getAnyTypeForObject(exception.ToString()));
            // Get the inner exception for more details
            exception = exception.get_InnerException();
        }
    } 

Wednesday, June 5, 2013

AxInternalBase Class

The AxBC table classes have the following characteristics:
  • A One-to-one relationship between class and table.
  • The classes use the same name, with an Ax prefix, as the corresponding table. For example, the AxSalesTable class changes records in the SalesTable table.
  • The interface methods on the AxBC table class for fields in the related table use the same name, with a prefix of parm, as the fields on the table.For example, the parmCustAccount method on the AxSalesTable class is used externally to set or get the value of the CustAccount field in the SalesTable table.
  • The classes change the table records directly by setting the values of the table field and executing the update and insert methods on the table.
  • The default business logic is performed in the methods the methods that have a prefix of set. For example the setCurrencyCode method on the AxSalesTable class is used internally to set the value of the CurrencyCode field in the SalesTable table, depending on the value in the CustAccount field.
http://msdn.microsoft.com/en-us/library/axinternalbase.aspx

 

Sunday, June 2, 2013

Interop

Add AX table directory to Visual Studio library project, use C# code to access AX data.
http://msdn.microsoft.com/EN-US/library/gg889200.aspx
  • Creating the class library, adding a Microsoft Dynamics AX table to the project, and accessing that table from code.
  • Creating a console application project and testing the generated assembly.

create user control for EP

Dynamics AX user controls are ASP.net user controls developed in Visual studio 2008, parked in Dynamics AX application and can be used in Enterprise portal.
In section 1, I explained about how to create a simple user controls and in section 2, I explained about how to connect the web parts and in section 3, I explained about how to call X++ methods within the web part.

Section 1
Create a Dynamics web project in visual studio:
Open visual studio 2008.
File ->New ->Web site.
In new website selection screen select the template ‘Dynamics AX web project’ under ‘My templates’ section.
Select Location as HTTP and provide the project name
Language: Visual C#
A new solution will be created with a project.
Right click the solution project and select ‘Add New Item’.
Select the ‘Dynamics AX User control’ as template which is under ‘My templates’.
Provide the name of the control.(SampleUserControl)
Select the language as the C#. Click OK.
New control “SampleUserControl” will be added to project.
Add the control to Dynamics AX AOT :
Right click the control and select “Add to AOT’. The user control will be added to AOT under AOT/Web/Webfiles/Web Controls.
Also a managed content item will be created under AOT/Web/Web Content/Managed which is pointing to user control SampleUserControl. This managed content item will be visible in enterprise portal.
Create a dataset in AX
Data set acts as a data source for the user control. Data sets can be created in AOT.
Under AOT/data sets, Create a new data set and name it as CustomerSample.
Data sets look exactly like the AX forms without design node.
For the CutomerSample data set add CustTable as the data source.
Save the dataset.
Design the control in visual studio:
Now go to visual studio and right click the sampleUserControl and click view designer.
Design mode of the control will be opened.
Now open the tool box and you find the Dynamics AX group in the tool box.(If it is not available then right click on tool bar and choose items they are available in .Net Framework Components tab)
Add the AXDataSource from the tool box.
Rename the data source to SampleCustDS.
Select the SampleCustDS in design mode and click > mark at the right top corner.
It asks for Dataset name. Select the ‘CustomerSample’ that you have created in AOT.
Now add AX grid view.
Select the AX grid view and open the properties screen and select the datasource as SampleCustDS and then > mark and then Edit columns option.
Under available fields from bound fields add AccountNum,Name, InvoiceAccount,CustGroup, Currency to selected fields.
Now right click the SampleUserControl and select ‘Refresh AX user control’. This will refresh the changes to AOT.
Creating a web part page and adding user control to it:
Now open Enterprise portal and select site actions and then create.
Select web part page under web pages.
Give the name of the page as “CustomerSample” and then choose the layout.
Select the document library as “Enterprise portal”.
A new blank page will be created.
Here we need to add the required web parts.
Under the body section click “add a web part”.
From the dialog opened select the “Dynamics User control web part” to hold the user control that we have just created and then click ‘Add’.
A blank Dynamics User control web part will be added. Now go to Edit at the right corner of the web part and click the arrow mark and then modify shared web part from the context menu.
Dynamics AX web part properties editing window will be opened to the right of the page.
Under the managed content item select the “SampleUserControl” managed content item. Click Apply and then OK.
Exit the edit mode by clicking exit edit mode below the site actions.
This will display the data from the Custtable in the design that you have created in visual studio.
Section 2
Go to visual studio 2008.
Add a new control named “CustomerContacts” to the same project that you have created above. Go to design part and add the AXDataSource’ control and rename to ‘CustDS’ and point to same dataset “CustomerSample”.
Add the AX form control and Select the datasource as ‘CustDS’ that you have created just now by clicking on > at the top right of form control. Select the datamember property(CustTable_current) also from properties window in visual studio.
Add an AXGroup inside AX form from tool box.
Select the AX group and go to properties window. For the fields property click on … symbol. A new window opens.
Select the required fields like Address, Phone, TeleFax, URL, Email etc,.
Add the user control to AOT.
Now go to the same EP page that you have created in section I above and add the new user control web part and point to the “CustomerContacts” managed content item.
Connecting two web parts:
By selecting the modify shared web part option, open the Dynamics properties window for first web part (SampleUserControl) and make the web part role as provider.
Open the Dynamics properties window for second web part (CustomerContacts) and make the role as Consumer to make this web part the consumer of information.
Now apply the changes by clicking on Apply.
Now on the first web part click on Edit and then connections àSend AX contextList to and then select the second web part.
You can verify it from the second web part; here it shows as ‘Connections àGet AXContextList from àfirst web part name.
Now if you change the section in the first web part that is if the customer selection is changed in grid the contact details for customer will automatically be changed in the second web part.
Section 3
In the first two examples we have written user controls without writing a single line of C# code. And we did not call X++ methods explicitely. But, sometimes it may be required to call the X++ class methods or table methods to get the related information. For example if the customer type is organization then we may need to get the number of employees, organization number of the customer (These details can be seen on Details tab of CustTable form in rich client.) Which are being stored in table DirOrganizationDetail. In the same way if the customer type is person we may need BirthDate and MarritalStatus which are stored in DirPersonPartyDetail. This we can achieve by writing a code in C# to call X++ methods.
I will explain how to get these details by calling table methods.
Import the below namespaces before adding the following lines of code.
Microsoft.Dynamics.Framework.BusinessConnector.Adapter
Microsoft.Dynamics.Framework.BusinessConnector.Session
For the above control CustomerContacts add the field lblNumberOfEmployees. This will display the number of employees in the selected customer organization.
In the pade_load () of CustomerContacts write the following line if code.
AxBaseWebPart.GetWebpart(this).ExternalContextChanged+=new EventHandler<Microsoft.Dynamics.Framework.Portal.UI.AxExternalContextChangedEventArgs>(CustomerContacts_ExternalContextChanged);
And write the event hander for ‘CustomerContacts_ExternalContextChanged’ like below
void CustomerContacts_ExternalContextChanged(object sender, Microsoft.Dynamics.Framework.Portal.UI.AxExternalContextChangedEventArgs e)
{
IAxaptaRecordAdapter currentRecord = AxBaseWebPart.GetWebpart(this).ExternalRecord;
ISession currentSession = AxBaseWebPart.GetWebpart(this).Session;
IAxaptaRecordAdapter recordAdapter;
object obj1,obj2;
string partyId;
IAxaptaAdapter axAdapter = currentSession.AxaptaAdapter;
obj1 = axAdapter.CallStaticRecordMethod(“CustTable”, “find”, currentRecord.GetField(“AccountNum”).ToString());
recordAdapter = axAdapter.CreateAxaptaRecord(obj1);
partyId = recordAdapter.GetField(“partyId”).ToString();
obj2=axAdapter.CallStaticRecordMethod(“DirOrganizationDetail”,”find”,partyId);
recordAdapter = axAdapter.CreateAxaptaRecord(obj2);
lblNumberOfEmployees.Text = recordAdapter.GetField(“NumberOfEmployees”).ToString();
}
Here first I get the customer record by passing the customer id that was selected in the grid.
And then get the party id of the customer from the customer record. Pass the party id to find method of DirOrganizationDetail to get the DirOrganizationDetail record.
From DirOrganizationDetail we can get number of employees directly.

Post from: http://blogs.bojensen.eu/?p=225

Saturday, June 1, 2013

Debug User Control

Debug User Control:
  • Open the Default.aspx page that is part of your EP Web Application project. This is an ASP.NET page that can host web parts needed for testing User Controls. The Default.aspx page is automatically included in any EP Web Application project you create.
  • Configure the web parts on the Default.aspx page.
  • Add any EP Proxy Projects that are required for your EP Web Application project.
  • Run the Default.aspx page.

    http://msdn.microsoft.com/EN-US/library/cc616458.aspx 
How to debug user controls
http://msdn.microsoft.com/EN-US/library/cc567649.aspx

Create EP Web App,
Add an User Control
Add ManagedContentItem to Default.aspx
Add EP Proxy Project (VS->Project->add AOT Proxy Project)
Run Default.aspx

 ManagedConentItem in general is the usercontrol name.

How to modify an user control
http://ajstudi0.blogspot.com/2013/02/walkthrough-adding-field-to-user.html