2013年4月11日星期四
Dynamics AX 2012 SSRS reports patterns
Here are the design pattern/changes that we need to make sure for AX 2012 SSRS report development:
Functional Area
|
AX2009
|
AX2012
|
Input parameters (definition)
|
Report
|
Data contract (*)
|
Input parameters (validation)
|
Report
|
Data contract (*)
|
Input dialog (simple)
|
Report
|
Data contract (*)
|
Input dialog (complex)
|
Report
|
UI Builder (*)
|
Input parameters (modification)
|
Report
|
Controller (*)
|
Dynamic query
|
Report
|
Query
|
Report data
|
Report
|
Table (temp)
|
Business logic
|
Report
|
RDP
|
Report layout
|
Report
|
SSRS Report
|
Open Dynamics ax in specific language
To open MS Dynamics AX in specific language via a command, you can use it in following manner:
1. Open commoand prompt.
2. Type Ax32.exe –language=culture_id
Example : Ax32.exe –language=en-us
1. Open commoand prompt.
2. Type Ax32.exe –language=culture_id
Example : Ax32.exe –language=en-us
How to using x++ release products to the legal entities
In this post, I would like to share X++ Code that will help to release products to the legal entities from product master.
static void THK_releaseProductsWithJob(Args _args)
{
EcoResProduct ecoResProduct;
InventTable inventTable;
InventTableModule inventTableModule;
NumberSequenceTable numberSequenceTable;
ItemId itemId;
InventItemSetupSupplyType inventItemSetupSupplyType;
EcoResStorageDimensionGroupProduct ecoResStorageDimensionGroupProduct;
EcoResTrackingDimensionGroupProduct ecoResTrackingDimensionGroupProduct;
EcoResStorageDimensionGroupItem ecoResStorageDimensionGroupItem;
EcoResTrackingDimensionGroupItem ecoResTrackingDimensionGroupItem;
;
select firstOnly ecoResProduct where EcoResProduct.DisplayProductNumber == "test"; //Audio system
changecompany ('CEU')
{
ttsBegin;
inventTable = null;
inventTableModule = null;
inventItemSetupSupplyType = null;
ecoResStorageDimensionGroupProduct = null;
ecoResTrackingDimensionGroupProduct = null;
ecoResStorageDimensionGroupItem = null;
ecoResTrackingDimensionGroupItem = null;
numberSequenceTable = InventParameters::numRefItemId().numberSequenceTable();
//get item id from:
//1. Product number if number seq for item ID is not set up or manual or return blank value
if (!numberSequenceTable.RecId || numberSequenceTable.Manual)
{
itemId = ecoResProduct.productNumber();
}
else //number sequence auto, get a number
{
itemId = NumberSeq::newGetNumFromId(numberSequenceTable.RecId).num();
}
inventTable.initValue();
inventTable.initFromEcoResProduct(ecoResProduct);
inventTable.ItemId = ItemId;
inventTable.NameAlias = ecoResProduct.SearchName;
inventTable.insert(true);
// Create inventTableModules
inventTableModule.initValue();
inventTableModule.ItemId = inventTable.ItemId;
inventTableModule.ModuleType = ModuleInventPurchSales::Invent;
inventTableModule.insert();
inventTableModule.initValue();
inventTableModule.ItemId = inventTable.ItemId;
inventTableModule.ModuleType = ModuleInventPurchSales::Purch;
inventTableModule.insert();
inventTableModule.initValue();
inventTableModule.ItemId = inventTable.ItemId;
inventTableModule.ModuleType = ModuleInventPurchSales::Sales;
inventTableModule.insert();
//Create inventItemLocation
InventItemLocation::createDefault(inventTable.ItemId);
// Creates a new item default order type for the product that is released.
inventItemSetupSupplyType.initValue();
inventItemSetupSupplyType.ItemId = inventTable.ItemId;
inventItemSetupSupplyType.ItemDataAreaId = inventTable.DataAreaId;
inventItemSetupSupplyType.insert();
//create relationship tables to dimension groups.
ecoResStorageDimensionGroupProduct = EcoResStorageDimensionGroupProduct::findByProduct(ecoResProduct.RecId);
ecoResTrackingDimensionGroupProduct = EcoResTrackingDimensionGroupProduct::findByProduct(ecoResProduct.RecId);
if (ecoResStorageDimensionGroupProduct.RecId)
{
// mandatory storage dimension group for the product
ecoResStorageDimensionGroupItem.ItemDataAreaId = inventTable.DataAreaId;
ecoResStorageDimensionGroupItem.ItemId = inventTable.ItemId;
ecoResStorageDimensionGroupItem.StorageDimensionGroup = ecoResStorageDimensionGroupProduct.StorageDimensionGroup;
ecoResStorageDimensionGroupItem.insert();
}
if (ecoResTrackingDimensionGroupProduct.RecId)
{
// mandatory tracking dimension group for the product
ecoResTrackingDimensionGroupItem.ItemDataAreaId = inventTable.DataAreaId;
ecoResTrackingDimensionGroupItem.ItemId = inventTable.ItemId;
ecoResTrackingDimensionGroupItem.TrackingDimensionGroup = ecoResTrackingDimensionGroupProduct.TrackingDimensionGroup;
ecoResTrackingDimensionGroupItem.insert();
}
ttsCommit;
info("Product successfully released to CEU legal entity");
}
}
2013年4月10日星期三
How to using .net parsing Date Strings
Dynamics AX provides functions for parsing date strings into a date object but they are limited at best.
The following static method uses the .Net date parsing functionality to create a X++ date object from any valid date string without knowing the year, month, and day sequence or anything else about it for that matter.
It also allows you to specify the value that is returned in case of an invalid string being passed.
The following static method uses the .Net date parsing functionality to create a X++ date object from any valid date string without knowing the year, month, and day sequence or anything else about it for that matter.
It also allows you to specify the value that is returned in case of an invalid string being passed.
static date ParseDateString(str _dateValue, date _default = datenull())
{
date res;
int infoCnt;
;
new InteropPermission(InteropKind::ClrInterop).assert();
try
{
infoCnt = infolog.line();
res = System.DateTime::Parse(_dateValue);
}
catch
{
res = _default;
infolog.clear(infoCnt);
}
CodeAccessPermission::revertAssert();
return res;
}
How to transfer CLR Array to AX List
If you use any amount of CLRInterop programming in Dynamics AX you have probably at some point or another needed to use X++ code to interact with an array object passed back from a bit of CLR code.
I created the following static class to ease the process of converting a CLRArray object into a X++ style list object.
It only requires two parameters to be passed for the conversion:
I created the following static class to ease the process of converting a CLRArray object into a X++ style list object.
It only requires two parameters to be passed for the conversion:
- CLRObject _input – this is the object array you need converted.
- Types _type – this is the X++ type that you want the individual CLR objects converted to.
static List CLRArrayToList(CLRObject _input, Types _type)
{
System.Collections.ArrayList list;
List l = new List(_type);
AnyType x;
int cnt, i;
;
new InteropPermission(InteropKind::ClrInterop).assert();
try
{
list = new CLRObject('System.Collections.ArrayList',_input);
cnt = list.get_Count();
for(i = 0; i < cnt;i++)
{
x = CLRInterop::getAnyTypeForObject(list.get_Item(i));
l.addEnd(x);
}
}
catch
{
l = new List(_type);
}
CodeAccessPermission::revertAssert();
return l;
}
To utilize the method add it to a class (we will name it QuickTools for this example) and call it like this:CLRObject bytes;
List intList = new List(Types::Integer);
// Some code here to populate the bytes object with numeric values
intList = QuickTools::CLRArrayToList(bytes,Types::Integer);
// intList now contains the values stored in bytes
Using this example and a bit of creativity you could create a static method to perform the opposite action and convert a X++ list into a CLR Array object
2013年3月21日星期四
How to updated the caller Form/DataSource
If we need to notify events to the caller form we can try this pattern:
In the child form, make a method named updateCaller and invoke it when you want to notify the parent:
Implement the handling method in the parent form:
Or if you prefer, in the DataSource:
Invoking it from a simple button inside the child form:
See a pratical sample in the form MarkupTrans (DataSource -> method write).
In the child form, make a method named updateCaller and invoke it when you want to notify the parent:
void updateCaller() { Common common; Object dataSource; Object caller; ; //----------------------------------- //We are notifying using the dataSource common = element.args().record(); if (common && common.isFormDataSource() && formDataSourceHasMethod(common.dataSource(), identifierstr(SomethingWasHappend))) { dataSource = common.dataSource(); dataSource.SomethingWasHappend(); } //----------------------------------- //----------------------------------- //We are notifying using the form caller = element.args().caller(); if (caller && classidget(caller) == classnum(SysSetupFormRun) && formHasMethod(caller, identifierstr(SomethingWasHappend))) { caller.SomethingWasHappend(); } //----------------------------------- }
Implement the handling method in the parent form:
void SomethingWasHappend() { ; info("Something was happend (Form)"); }
Or if you prefer, in the DataSource:
void SomethingWasHappend() { ; info("Something was happend (DataSource)"); }
Invoking it from a simple button inside the child form:
void clicked()
{
super();
element.updateCaller();
}
See a pratical sample in the form MarkupTrans (DataSource -> method write).
订阅:
博文 (Atom)