Posts tagged with: X++

Date Lookup in a String Control

Sometimes, you may need to lookup the date calendar in a string control. This was easily possible by overriding the lookup function and call the below method in the AX older versions.

public void lookup()
{
    ;

    this.performFormLookup(SysLookup::LookupDate());
}

But in AX2012R2 you cannot use the lookupDate function like this because it is made protected and can only be used by functions in the classes which are derived from SysLookup.

Its work around is to directly call the SysDateLookup form.

The code is as below.

public void lookup() // Form control lookup
{
    FormRun formRun;
    Args    args;
    ;

    args        = new Args(formStr(SysDateLookup));
    args.caller(element);
    formRun     = classfactory.formRunClass(args);
    formRun.init();
    this.performFormLookup(formRun);
}

Happy DAXing!


Microsoft Dynamics AX Job – Eliminate Duplicate Barcode issue

I wrote a job that eliminated the duplicates barcode issue in AX 2012. The job goes through the list of the barcodes, finds duplicated barcodes and adds a D and a counter value at their beginning.  Duplicated barcodes, which are renamed after running this job, can always be found easily by getting a list of the barcodes starting with the letter “D”.

I am sharing the code here:

static void EliminateDuplicateBarcodes(Args _args)
{
    InventItemBarcode inventItemBarcode,inventItemBarcode1;
    int counter;

    counter=1;

    while select itemBarCode,RecId from inventItemBarcode where inventItemBarcode.itemBarCode != ''
    {
        while select forUpdate itemBarCode,recid from inventItemBarcode1
            where inventItemBarcode1.itemBarCode == inventItemBarcode.itemBarCode
                && inventItemBarcode1.RecId != inventItemBarcode.RecId
        {
            ttsBegin;
            inventItemBarcode1.itemBarCode = strFmt("D%1-%2",counter,inventItemBarcode1.itemBarCode);
            inventItemBarcode1.update();
            ttsCommit;

            counter++;
        }

    }

}

Happy Coding :)


Region as an Internal Organisation

System should allow users to create Region within the internal organization hierarchy. For this we have to do some customization

First create new operating unit type element in OMOperatingUnitType base enum

f1

OMOperatingUnitType is used in OMOperatingUnit tables so we need to Restore OMOperatingUnit tables.

Create new View which named as DimAttributeOMRegion as shown in below screen

f2

 Create Internal Region Organization type

Organization Administration > Common > Organization > Internal Organization

Create new region from Internal Organization action pane button as shown in below screen

f3

Click Ok

f4

General Ledger > Setup > Financial Dimensions > Financials Dimensions

Newly created organization should appear within Financial Dimension Form and could be used throughout AX.

f5


Customize Existing Number Sequence to Fiscal Year Number Sequence

Here we are customizing existing Number sequence and convert it in to Fiscal year number sequence Many customer demands for Purchase order creation with automatic year means how to add year to a number sequence in AX2012, e.g. to generate IDs such as 2013-xxxxx and 2014-xxxxx, that would automatically use the current year. Some people understand that number sequence scopes should allow that, but they don’t know how, from very little bit of customization we can automate purchase order number sequence with year

Customize Purchase order Number Sequence Class:

Add fiscal calendar parameter in NumberSeqModulePurchaseIOrder (LoadModule) method as shown in below screen

 datatype.addParameterType(NumberSeqParameterType::FiscalCalendarPeriod, true, true);
fk1

Load NumberSeqModulePurchaseIOrder (Load Module) method Through Job

 NumberSeqModulePurchaseOrder NumberSeqModulePurchaseOrder = new NumberSeqModulePurchaseOrder();
NumberSeqModulePurchaseOrder.load();
fk2

Before going to run the Job, Remove purchase order existing scope parameter record in NumberSequenceDatatype table, if we don’t remove previous Purchase order scope parameter record it will not effect in Segment configuration as shown below

CEU/Organization administration/Number Sequence/ Segment configuration

fk3

Add Fiscal Year Relation to PurchParamater Table:

CEU/Procurement and sourcing/procurement and Sourcing parameters

fk4

We have customized procurement and Sourcing parameters form for Purchase order Fiscal Number sequence, because we need to select which Fiscal year the purchase order is created every year.

Add fiscal year table relation to PurchParamter table

fk5

Add a fiscal year Field on Procurement and Sourcing parameters form

fk6

Customize Purchase Order Number Sequence Table (PurchParameter):

Add following code in Purchase order Number sequence Parameter table method (numRefPurchId), in this existing method we have change code according to fiscal year.

static client server NumberSequenceReference  numRefPurchId(TransDate _date = systemdateget())
{
   //
   PurchParameters PurchParameters;
   NumberSeqScope  scope;

select firstOnly PurchParameters; // get Selected fiscal year in 
                                  // procurement and    Sourcing parameters Form 

   scope = NumberSeqScopeFactory::CreateDataAreaFiscalCalendarPeriodScope
                            (curext(),FiscalCalendars::findPeriodByPeriodCodeDate(FiscalCalendar::findByCalendarId(PurchParameters.FiscalCalendar).RecId, _date).RecId);
   //

     return NumberSeqReference::findReference(extendedTypeNum(PurchId),scope);
}
fk7

Fiscal Year Number Sequence Configuration

 

General ledger -> Setup -> Fiscal calendars.

Create a new Fiscal year or use existing Fiscal year, but In our case we have created our own Fiscal year for Ten years because we need to create Purchase order automated for Ten years

fk8

If you want to add more years follow below screen.

fk9

Click the Calendar -> Calendar year -> New fiscal year button.

Change Copy from last fiscal year from ‘true’ to ‘false’.

Change Unit from ‘Months’ to ‘Years’.

Click the Create button.

Close the Fiscal calendars form.

Number sequences creation

 

fk10

 

Click Area Page node: Organization administration -> Common -> Number sequences -> Number sequences. Click the Number sequence -> New -> Number sequence button.

fk11

Change Number sequence code from ” to ‘POFiscal’.

Change Name from ” to ‘2013’.

Change Scope from ‘Shared’ to ‘Company and Fiscal calendar period’.

Change Company from ” to ‘ceu’.

Change Calendar from ” to ‘FiscalYear’.

Change Fiscal year from ” to ‘2013’.

Change Period name from ” to ‘Period 1′.

fk12

 

Make it very clear that we are creating PO number sequence for the year 2013 and we have to create PO number sequence again for Year 2014, 2015, 2016.xxxxxx 2023 with same Number sequence Code i.e. ‘POFiscal’  as shown in below screen for Year 2014

fk13

 

Creating Purchase orders:

Before going to create Purchase order make sure that Fiscal year must be selected in Procurement and sourcing Parameter form which we have customized earlier above

fk14

 

This selected Fiscal year must be same which we have selected in creating Purchase order Fiscal year Number Sequence.


Consuming External Web Service through a .Net Class Library Wrapper in Microsoft Dynamics AX 2009

Direct referencing a web service in AOT may lead to different issues some times when it comes to use service reference in the x++ code.

I will show you a simple recipe of how we can consume an external web service in AX2009 by wrapping this web service into a .net assembly wrapper.

Open a visual studio, create a new project.
Select the .net class library as template.
Give it a meaning full name so it can be accessed from x++ code.

th1

th2

Add a web service reference, I’m using a public WSDL of the currency convert.
Click Ok and build the project.
Now right click on the project and go to the project directory.
Copy the dll from bin and rename app.config file to AX32Srv.exe and AX32.exe.
Copy these files to the directory of AOS server and the bin of client if needed.
Restart the AOS.
Now you can consume this webservice from x++ code.
ServiceWrapper.ServiceReference .
If you don’t copy the config file to AOS bin you face this error because It does not read the end points from configuration file when instantiating the service client.

 System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. —> System.InvalidOperationException: Could not find default endpoint element that references contract ‘ServiceReference1.ICyclelutionService’ in the ServiceModel client configuration section. This might be because no configuration file was found for your application, or because no endpoint element matching this contract could be found in the client element.

 at System.ServiceModel.Description.ConfigLoader.LoadChannelBehaviors(ServiceEndpoint serviceEndpoint, String configurationName)

 at System.ServiceModel.ChannelFactory.ApplyConfiguration(String configurationName, Configuration configuration)

 at System.ServiceModel.ChannelFactory.ApplyConfiguration(String configurationName)

 at System.ServiceModel.ChannelFactory.InitializeEndpoint(String configurationName, EndpointAddress address)

 at System.ServiceModel.ChannelFactory`1..ctor(String endpointConfigurationName, EndpointAddress remoteAddress)

at System.ServiceModel.ConfigurationEndpointTrait`1.CreateSimplexFactory()

at System.ServiceModel.ConfigurationEndpointTrait`1.CreateChannelFactory()

 at System.ServiceModel.ClientBase`1.CreateChannelFactoryRef(EndpointTrait`1 endpointTrait)

 at System.ServiceModel.ClientBase`1.InitializeChannelFactoryRef()

 at System.ServiceModel.ClientBase`1..ctor()

 at ServiceRef.ServiceReference1.CyclelutionServiceClient..ctor()

— End of inner exception stack trace —

 at System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean noCheck, Boolean& canBeCached, RuntimeMethodHandleInternal& ctor, Boolean& bNeedSecurityCheck)

 at System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark)

at System.RuntimeType.CreateInstanceDefaultCtor(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark)

 at System.Activator.CreateInstance(Type type, Boolean nonPublic)

at System.RuntimeType.CreateInstanceImpl(BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes, StackCrawlMark& stackMark)

 at System.Activator.CreateInstance(Type type, BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes)

at System.Activator.CreateInstance(Type type, Object[] args)

at Microsoft.Dynamics.AX.ManagedInterop.ClrBridgeImpl.NewClrObject(ClrBridgeImpl* , Char* pszClassName, Char* assemblyName, Int32 argsLength, ObjectWrapper** arguments, Boolean* isException

Another way to wrap the web service is to wrap it in a web service project in VS. But for that, the web service must be hosted to IIS.

 


Creating a Customer Form at Run Time in X++

The job “CustomerForm” creates a customer form at run time in x++. In the form, I have used two datasources “CustTable” and “DirPartyTable”. I have also shown how to add menuitemfunctions in a form through X++.

Here is the code in X++:

public static void CustomerForm(Args _args)
{
//Initialization
DictTable dictTable;
DictTable dictTable1;
Form form;
FormBuildDesign design;
FormBuildDataSource formBuildDataSource;
FormBuildDataSource formBuildDataSource1;
FormBuildActionPaneControl actionPane;
FormBuildActionPaneTabControl actionPaneTab;
FormBuildButtonGroupControl buttonGroup1;
FormBuildButtonGroupControl buttonGroup2;
FormBuildCommandButtonControl CommandNew;
FormBuildCommandButtonControl CommandDelete;
FormBuildMenuButtonControl CustomerButton;
FormBuildFunctionButtonControl NewCustomerButton;
FormBuildFunctionButtonControl ForecastButton;
FormBuildGroupControl Grp;
FormBuildGridControl grid;
FormBuildGroupControl grpBody;
Args args;
FormRun formRun;
#task

//Adding DataSources
dictTable1 = new DictTable(tableNum(CustTable));
dictTable = new DictTable(tableNum(DirPartyTable));
form = new Form();
form.name(“Customer Overview”);

formBuildDataSource = form.addDataSource(dictTable.name());
formBuildDataSource.table(dictTable.id());

formBuildDataSource1 = form.addDataSource(dictTable1.name());
formBuildDataSource1.table(dictTable1.id());
//Building Form Design
design = form.addDesign(‘Design’);
design.caption(“Overview”);
design.style(FormStyle::SimpleList);
design.titleDatasource(formBuildDataSource.id());
//Adding Action Pane and Buttons
actionPane = design.addControl(
FormControlType::ActionPane, ‘ActionPane’);

actionPane.style(ActionPaneStyle::Strip);
actionPaneTab = actionPane.addControl(FormControlType::ActionPaneTab, ‘ActionPaneTab’);

buttonGroup1 = actionPaneTab.addControl(FormControlType::ButtonGroup, ‘NewDeleteGroup’);
buttonGroup2 = actionPaneTab.addControl(FormControlType::ButtonGroup, ‘ButtonGroup’);

CommandNew = buttonGroup1.addControl(FormControlType::CommandButton, ‘NewButton’);
CommandNew.buttonDisplay(FormButtonDisplay::TextAndImageLeft);
CommandNew.normalImage(‘11045′);
CommandNew.imageLocation(SysImageLocation::EmbeddedResource);
CommandNew.primary(NoYes::Yes);
CommandNew.command(#taskNew);

CommandDelete = buttonGroup1.addControl(FormControlType::CommandButton, ‘NewButton’);
CommandDelete.text(“Delete”);
CommandDelete.buttonDisplay(FormButtonDisplay::TextAndImageLeft);
CommandDelete.normalImage(‘10121′);
CommandDelete.imageLocation(SysImageLocation::EmbeddedResource);
CommandDelete.saveRecord(NoYes::Yes);
CommandDelete.primary(NoYes::Yes);
CommandDelete.command(#taskDeleteRecord);

CustomerButton = buttonGroup2.addControl(FormControlType::MenuButton, ‘CustomerquickCreate’);
CustomerButton.helpText(“Create New Customer”);
CustomerButton.text(“Customer”);

NewCustomerButton = CustomerButton.addControl(FormControlType::MenuFunctionButton, ‘CustomerquickCreate’);
NewCustomerButton.text(‘New’);
NewCustomerButton.saveRecord(NoYes::No);
NewCustomerButton.dataSource(formBuildDataSource.id());
NewCustomerButton.menuItemName(menuitemDisplayStr(CustomerquickCreate));
ForecastButton = buttonGroup2.addControl(FormControlType::MenuFunctionButton, ‘SalesForecast’);
ForecastButton.text(‘Forecast’);
ForecastButton.saveRecord(NoYes::No);
ForecastButton.menuItemName(menuitemDisplayStr(ForecastSalesGroup));
//Body
grpBody = design.addControl(FormControlType::Group, ‘Body’);
grpBody.heightMode(FormHeight::ColumnHeight);
grpBody.columnspace(0);
grpBody.style(GroupStyle::BorderlessGridContainer);

grid = grpBody.addControl(FormControlType::Grid, “Grid”);
grid.dataSource(formBuildDataSource.name());
grid.widthMode(FormWidth::ColumnWidth);
grid.heightMode(FormHeight::ColumnHeight);
grid.addDataField(formBuildDataSource.id(), fieldNum(DirPartyTable,Name));
grid.addDataField(formBuildDataSource1.id(), fieldNum(CustTable,AccountNum));
grid.addDataField(formBuildDataSource.id(), fieldNum(DirPartyTable,LanguageId));

Grp = design.addControl(FormControlType::Group, ‘Group’);

ForecastButton = Grp.addControl(FormControlType::MenuFunctionButton, ‘SalesForecast’);
ForecastButton.text(‘Forecast’);
ForecastButton.menuItemName(menuitemDisplayStr(ForecastSalesGroup));

args = new Args();
args.object(form);

formRun = classFactory.formRunClass(args);
formRun.init();
formRun.run();
formRun.detach();
}


Finding the occurrence of string within another string through X++

X++ offers a lot of string functions to be used on the strings. Here, we will be using the “strscan” function. The “strscan” searches for a string within another string

————————————————————————————————————-

The strscan function takes the following arguments

Strscan (str text, str characters, int position, int number);

Text: The target string

Characters: The string to be found

Position: The first position in the target string to perform the search

Number: Number of times search will be performed. Normally, it is the length of the original string. If a negative sign is used in this argument, the search operation is performed in the reverse order

————————————————————————————————————-

Below is the code to find any character in a string.

int position;

str targetstring = “ABCD”

position = strscan( targetstring, “CD”,3,strlen(targetstring);

if (position)

{

info(“Found”);

}

else

{

info(“Not Found”);

}