2012年10月29日星期一
How to using code create purchase order
Purchase Order using X++
In this post we will learn the below using X++ :
1) How to Create Purchase Order
2) How to Create Purchase Order Line
3) How to Post Purchase Order
static void THK_createPurchaseOrder(Args _args)
{
PurchTable purchTable;
PurchLine pline;
NumberSeq ns;
PurchID pid;
PurchFormLetter pl;
;
//Create Purchase Order
ns = NumberSeq::newGetNumFromCode(SalesParameters::numRefSalesId().NumberSequence);
purchTable.initValue();
pid = ns.num();
purchTable.PurchId = pid;
purchTable.OrderAccount = "4202";
purchTable.initFromVendTable();
purchTable.insert();
//Create Purchase Line
pline.clear();
pline.PurchId = pid;
pline.ItemId = "1109";
pline.createLine(NoYes::Yes,NoYes::Yes,NoYes::Yes,NoYes::Yes,NoYes::Yes,NoYes::Yes);
info("Purchase Order Created Sucessfully");
//Post the PO
pl = PurchFormLetter::construct(DocumentStatus::Invoice);
pl.update(PurchTable::find(pid), pid, SystemDateGet(),PurchUpdate::All,AccountOrder::None,false,true);
info("Posted Sucessfully");
}
How to using code create and post inventory jounral
Create & Post Inventory Journal in AX 2009
Following is job which will create and post the Inventory Journal in ax 2009
static void THK_createMovJournal(Args _args)
{
InventJournalTable journalTable;
InventJournalTrans journalTrans;
InventJournalTableData journalTableData;
InventJournalTransData journalTransData;
InventTable inventTable;
inventDim tmpinventDim;
Counter cnt;
InventJournalCheckPost journalCheckPost = new InventJournalCheckPost();
DialogButton dbtn;
;
journalTableData = JournalTableData::newTable(journalTable);
journalTransData = journalTableData.journalStatic().newJournalTransData(journalTrans,journalTableData);
// create JournalTable
journalTable.clear();
journalTable.JournalId = journalTableData.nextJournalId();
journalTable.JournalType = InventJournalType::Movement;
journalTable.JournalNameId = journalTableData.journalStatic().standardJournalNameId(journalTable.JournalType);
journalTableData.initFromJournalName(journalTableData.journalStatic().findJournalName(journalTable.JournalNameId));
// create JournalTrans
select firstonly inventTable;
for(cnt=1;cnt<10;cnt++)
{
journalTrans.clear();
journalTransData.initFromJournalTable();
journalTrans.TransDate = systemdateget() + 1 div 2;
journalTrans.ItemId = '1103'; //inventTable.ItemId;
journalTrans.Qty = 100;
journalTrans.CostAmount = 100;
journalTrans.LedgerAccountIdOffset = '110170';
// Dimension details
tmpinventDim.InventLocationId = '11';
journalTrans.InventDimId ='00000061_069'; //InventDim::findOrCreate(inventDim).inventDimId;
journalTransData.create();
}
journalTable.insert();
// Call the static method to post the journal
if(InventJournalCheckPost::newPostJournal(journalTable).validate())
if(box::yesNo("Do you want to Post Now?",DialogButton::No)==DialogButton::Yes)
{
InventJournalCheckPost::newPostJournal(journalTable).run();
}
else
{
box::info("Not Posted");
}
info("done");
}
How to using code create sales order
/*sales Order using X++
Hi,In this post we will learn the below using X++ :
1) How to Create Sales Order
2) How to Create Sales Order Line
3) How to Post Sales Order
*/
public static void THK_createSalesOrderDemo(Args _s)
{
// Create the Sales Order
SalesTable salesTable;
SalesLine sl;
SalesId sid;
NumberSeq NumberSeq;
SalesFormLetter fl;
;
NumberSeq = NumberSeq::newGetNumFromCode(SalesParameters::numRefSalesId().numberSequence);
sid = NumberSeq.num();
//create sales order header
salesTable.SalesId = sid;
salesTable.initValue();
salesTable.CustAccount = "1101";
salesTable.initFromCustTable();
salesTable.insert();
//Create the Sales Line with the created Sales Order
sl.SalesId = sid;
sl.ItemId = "1109";
sl.CreateLine(NoYes::Yes,NoYes::Yes,NoYes::Yes,NoYes::Yes,NoYes::Yes,NoYes::Yes);
info("Sales Order Created with Line");
//How to Post the Sales Order Invoice
fl=SalesFormLetter::construct(DocumentStatus::Invoice);
fl.update(SalesTable::find(sid));
info("Sales Order Posted");
}
How to using code deploy SSRS Reports to AX 2012
Following code can be used to deploy SSRS reports in Ax 2012.
However make sure that this code runs from the client, and not as CIL (otherwise you will get run time errors)
I can run this below code as a job and works fine.
please Note : This code will only work in AX 2012 as in AX 2009/4.0/3.0 there were no SSRSReport Classes.
static void THK_deploySSRSReportDemo(Args _args)
{
SSRSReportManager mgr = new SSRSReportManager();
SSRSReportConceptNode node = new SSRSReportConceptNode();
;
node=TreeNode::findNode(@"\\SSRS Reports\Reports\SalesInvoice");
mgr.deploymentStart();
mgr.deployReport(node);
mgr.deploymentEnd();
}
How to Convert/Upgrade MorphX Report to SSRS in Dynamics AX
One of the major change in Dynamics AX 2012 is related to reporting services. Though we were able to develop some SSRS reports in AX 2009 as well with limitted framework functionality. However, in AX 2012 SSRS reporting framework is much more enhanced. Currently, you can import your AX traditional reports of MorphX in 2012 with no change. However, you cannot develop new MorphX reports in 2012. So this is the right time to move all your MorphX reports to SSRS as in future releases of AX MorphX framework will be completey removed.
In order to migrate AX reports to SSRS report following are some important points
1. Create a new query and make exactly the same query used in X++ report.
2. Move all your business logic to RDP (Report data provider) class.
3. AutoDesign reports of X++ will be replaced by AutoDesign in SSRS reports.
4. Generated Design on X++ report will be replaced by PrecisionDesign in SSRS reports.
Please have a look on the guidance to upgrade report here.
http://technet.microsoft.com/en-us/library/gg724106.aspx
How to revised(synchronization) table and field ID in Dynamics AX data dictionary
if a table ID or field ID is changed in Dynamics AX, data are lost during synchronization, because the table with the old ID (and containing data) is dropped at the beginning and then a new table is created with the same structure but a different ID.The same is valid analogically for table fields.The data loss can be prevented in several ways (e.g. by data export and reimport), but one solution is really simple and painless. Realize how the situation looks in AX after the ID change (e.g. after installation of a layer with different IDs) but before the database synchronization: Data are still in the database Table metadata in AOT contain the new ID Data in SqlDictionary table contain the old ID So it’s not necessary to export data or to put old IDs down, all information is still in the system. You just have to secure that synchronization is not run prematurely.You can identify all changed IDs by comparing values in AOT with values in SqlDictionary. And the update of SqlDictionary to the new ID can prevent the regeneration of database objects during synchronization. I use several scripts for this purpose, this is the simplest one:
The other day we upgraded to Cumulative Update 3 for Dynamics AX 2012. After that we got some problems in the SqlDictionary table - several table and field IDs did not much those in the AOT anymore.One of our developers found this post, which contained a job fixing such issues. We had to correct the job a bit, otherwise it failed when trying to process Views or update field IDs that had been "swapped" during upgrade (e.g. before: fieldId1 = 6001, fieldId2 = 6002; after installing CU3: fieldId1 = 6002, fieldId2 = 6001).This is the final version of the job. I know the change violates DRY principle, but for an ad-hoc job it is probably OK
static void THK_fixTableAndFieldIds(Args _args)
{
Dictionary dictionary = new Dictionary();
SysDictTable dictTable;
DictField dictField;
TableId tableId;
FieldId fieldId;
SqlDictionary sqlDictionaryTable;
SqlDictionary sqlDictionaryField;
setPrefix("Update of data dictionary IDs");
tableId = dictionary.tableNext(0);
ttsbegin;
while (tableId)
{
dictTable = new SysDictTable(tableId);
setPrefix(dictTable.name());
if (!dictTable.isSystemTable() && !dictTable.isView())
{
//Finds table in SqlDictionary by name in AOT, if ID was changed.
//Empty field ID represents a table.
select sqlDictionaryTable
where sqlDictionaryTable.name == dictTable.name()
&& sqlDictionaryTable.fieldId == 0
&& sqlDictionaryTable.tabId != dictTable.id();
if (sqlDictionaryTable)
{
info(dictTable.name());
//Updates table ID in SqlDictionary
if (ReleaseUpdateDB::changeTableId(
sqlDictionaryTable.tabId,
dictTable.id(),
dictTable.name())
)
{
info(strFmt("Table ID changed (%1 -> %2)", sqlDictionaryTable.tabId, dictTable.id()));
}
}
fieldId = dictTable.fieldNext(0);
//For all fields in table
while (fieldId)
{
dictField = dictTable.fieldObject(fieldId);
if (dictField.isSql() && !dictField.isSystem())
{
//Finds fields in SqlDictionary by name and compares IDs
select sqlDictionaryField
where sqlDictionaryField.tabId == dictTable.id()
&& sqlDictionaryField.name == dictField.name()
&& sqlDictionaryField.fieldId != 0
&& sqlDictionaryField.fieldId != dictField.id();
if (sqlDictionaryField)
{
//Updates field ID in SqlDictionary
if (ReleaseUpdateDB::changeFieldId(
dictTable.id(),
sqlDictionaryField.fieldId,
-dictField.id(),
dictTable.name(),
dictField.name())
)
{
info(strFmt("Pre-update: Field %1 - ID changed (%2 -> %3)",
dictField.name(),
sqlDictionaryField.fieldId,
-dictField.id()));
}
}
}
fieldId = dictTable.fieldNext(fieldId);
}
fieldId = dictTable.fieldNext(0);
//For all fields in table
while (fieldId)
{
dictField = dictTable.fieldObject(fieldId);
if (dictField.isSql() && !dictField.isSystem())
{
select sqlDictionaryField
where sqlDictionaryField.tabId == dictTable.id()
&& sqlDictionaryField.name == dictField.name()
&& sqlDictionaryField.fieldId < 0;
if (sqlDictionaryField)
{
//Updates field ID in SqlDictionary
if (ReleaseUpdateDB::changeFieldId(
dictTable.id(),
sqlDictionaryField.fieldId,
-sqlDictionaryField.fieldId,
dictTable.name(),
dictField.name())
)
{
info(strFmt("Final update: Field %1 - ID changed (%2 -> %3)",
dictField.name(),
sqlDictionaryField.fieldId,
-sqlDictionaryField.fieldId));
}
}
}
fieldId = dictTable.fieldNext(fieldId);
}
}
tableId = dictionary.tableNext(tableId);
}
ttscommit;
}
The other day we upgraded to Cumulative Update 3 for Dynamics AX 2012. After that we got some problems in the SqlDictionary table - several table and field IDs did not much those in the AOT anymore.One of our developers found this post, which contained a job fixing such issues. We had to correct the job a bit, otherwise it failed when trying to process Views or update field IDs that had been "swapped" during upgrade (e.g. before: fieldId1 = 6001, fieldId2 = 6002; after installing CU3: fieldId1 = 6002, fieldId2 = 6001).This is the final version of the job. I know the change violates DRY principle, but for an ad-hoc job it is probably OK
static void THK_fixTableAndFieldIds(Args _args)
{
Dictionary dictionary = new Dictionary();
SysDictTable dictTable;
DictField dictField;
TableId tableId;
FieldId fieldId;
SqlDictionary sqlDictionaryTable;
SqlDictionary sqlDictionaryField;
setPrefix("Update of data dictionary IDs");
tableId = dictionary.tableNext(0);
ttsbegin;
while (tableId)
{
dictTable = new SysDictTable(tableId);
setPrefix(dictTable.name());
if (!dictTable.isSystemTable() && !dictTable.isView())
{
//Finds table in SqlDictionary by name in AOT, if ID was changed.
//Empty field ID represents a table.
select sqlDictionaryTable
where sqlDictionaryTable.name == dictTable.name()
&& sqlDictionaryTable.fieldId == 0
&& sqlDictionaryTable.tabId != dictTable.id();
if (sqlDictionaryTable)
{
info(dictTable.name());
//Updates table ID in SqlDictionary
if (ReleaseUpdateDB::changeTableId(
sqlDictionaryTable.tabId,
dictTable.id(),
dictTable.name())
)
{
info(strFmt("Table ID changed (%1 -> %2)", sqlDictionaryTable.tabId, dictTable.id()));
}
}
fieldId = dictTable.fieldNext(0);
//For all fields in table
while (fieldId)
{
dictField = dictTable.fieldObject(fieldId);
if (dictField.isSql() && !dictField.isSystem())
{
//Finds fields in SqlDictionary by name and compares IDs
select sqlDictionaryField
where sqlDictionaryField.tabId == dictTable.id()
&& sqlDictionaryField.name == dictField.name()
&& sqlDictionaryField.fieldId != 0
&& sqlDictionaryField.fieldId != dictField.id();
if (sqlDictionaryField)
{
//Updates field ID in SqlDictionary
if (ReleaseUpdateDB::changeFieldId(
dictTable.id(),
sqlDictionaryField.fieldId,
-dictField.id(),
dictTable.name(),
dictField.name())
)
{
info(strFmt("Pre-update: Field %1 - ID changed (%2 -> %3)",
dictField.name(),
sqlDictionaryField.fieldId,
-dictField.id()));
}
}
}
fieldId = dictTable.fieldNext(fieldId);
}
fieldId = dictTable.fieldNext(0);
//For all fields in table
while (fieldId)
{
dictField = dictTable.fieldObject(fieldId);
if (dictField.isSql() && !dictField.isSystem())
{
select sqlDictionaryField
where sqlDictionaryField.tabId == dictTable.id()
&& sqlDictionaryField.name == dictField.name()
&& sqlDictionaryField.fieldId < 0;
if (sqlDictionaryField)
{
//Updates field ID in SqlDictionary
if (ReleaseUpdateDB::changeFieldId(
dictTable.id(),
sqlDictionaryField.fieldId,
-sqlDictionaryField.fieldId,
dictTable.name(),
dictField.name())
)
{
info(strFmt("Final update: Field %1 - ID changed (%2 -> %3)",
dictField.name(),
sqlDictionaryField.fieldId,
-sqlDictionaryField.fieldId));
}
}
}
fieldId = dictTable.fieldNext(fieldId);
}
}
tableId = dictionary.tableNext(tableId);
}
ttscommit;
}
If my memory isn’t failing me, this script works in AX4 – AX2012, but Axapta 3.0 doesn’t have changeTableId() a changeFieldId() methods in ReleaseUpdateDB and you have to implement them by yourself.
It is often forgotten that object IDs exist also in business data in database – one example is the ID of a table to which a document is attached. Ignoring this issue can affect database integrity, which is again felt by users as a data loss. One of possible solutions is to use my DataReferenceSearcher – although it actually doesn’t fix the found references, it helps you to write necessary data upgrade scripts.
How to using .net Regular Expression from Dynamics AX
static void THK_RegularExpression_Test()
{
int nameLen, numberLen;
str nameStr = "Vasan2th";
str numberStr = "1234";
str formatNumber, formatLetter;
boolean retName, retNumber;
System.Text.RegularExpressions.Regex regExLetter;
System.Text.RegularExpressions.Regex regExNumber;
System.Text.RegularExpressions.Match regMatch;
InteropPermission permission = new InteropPermission(InteropKind::ClrInterop);
;
nameLen = strLen(nameStr);
numberLen = strLen(numberStr);
formatNumber = strfmt(@"^[0-9]{%1}", numberLen);
formatLetter = strfmt(@"^[a-zA-Z ]{%1}", nameLen);
permission.assert();
//BP Deviation documented
regExLetter = new System.Text.RegularExpressions.Regex(formatNumber);
regMatch = regExLetter.Match(numberStr);
retNumber = regMatch.get_Success();
print "Is number format , ", retNumber; // Returns True;
regExNumber = new System.Text.RegularExpressions.Regex(formatLetter);
regMatch = regExNumber.Match(nameStr);
retName = regMatch.get_Success();
print "Is Letter format , ", retName; // Returns false;
pause;
}
How to delete all transactions from AX 2012
How to delete all transactions from AX 2012. Previously we were using SysDatabaseTransDelete class to do the same but as of now we need to modify that class to work properly with AX 2012 due to DB changes :
We need to modify the SysDatabaseTransDelete.handletable method with the below code :
void handleTable(SysDictTable sysDictTable)
{
TableGroup tableGroup;
if (tableSet.in(sysDictTable.id()))
return;
tableSet.add(sysDictTable.id());
if (sysDictTable && !sysDictTable.isTmp() && !sysDictTable.isMap())
{
tableGroup = sysDictTable.tableGroup();
// Handle company specific tables to be deleted
if (sysDictTable.dataPrCompany())
{
switch(tableGroup)
{
case TableGroup::Transaction:
case TableGroup::WorksheetHeader:
case TableGroup::WorksheetLine:
//FIX - Support new AX2012 transaction table types
case TableGroup::TransactionHeader:
case TableGroup::TransactionLine:
this.handleTransTable(sysDictTable);
break;
default:
this.handleNonTransTable(sysDictTable);
break;
}
}
else
{
// Handle global tables to be deleted
switch(tableGroup)
{
case TableGroup::Transaction:
case TableGroup::WorksheetHeader:
case TableGroup::WorksheetLine:
//FIX - Support new AX2012 transaction table types
case TableGroup::TransactionHeader:
case TableGroup::TransactionLine:
this.handleGlobalTransTable(sysDictTable);
break;
default:
break;
}
}
}
}
How to convert measurement from Char to MM on dyamics ax report
ReportControl 默认是100mm计量,传入参数Char2100mm(12)得到12 char的100mm长度值
reportControl.left100mm(Char2100mm(12,WidthHeight::Width));
reportControl.width100mm(Char2100mm(15,WidthHeight::Width));
reportControl.top100mm(Char2100mm(12,WidthHeight::Height));
reportControl.height100mm(Char2100mm(2,WidthHeight::Height));
所以增加以下方法可以用来计算Char和MM单位转换后的值。
public static real THK_Char2100mm(real _measurement,
WidthHeight _WidthHeight)
{
real convertedMeasurement;
;
if (_measurement)
{
switch (_WidthHeight)
{
case WidthHeight::Width :
convertedMeasurement = _measurement * 161;
break;
case WidthHeight::Height :
convertedMeasurement = _measurement * 361;
break;
}
}
else
{
convertedMeasurement = _measurement;
}
return convertedMeasurement;
}
How to achieved to copy data from origanl table instance to new table instance
One of the useful method from standard AX is the buf2Buf(), it behave similar to table's .data() method with one difference - buf2buf doesn't copy system field. Another reason of using buf2buf is copying of record from one company to another company. When using changeCompany(), the .data() method copy all field including DataAreaId and when insert(), DataAreaId field does not change, hence, the record is not inserted into the company indicated in the changeCompany(), here is where buf2Buf() comes in handy - copy all field except system field, then during insert(), let the system assign values to system field.
Sometimes, there're some functionality requires copy data from one table to another table which has similar structure (Eg. to history or logging table), in this case, the .data() and buf2Buf() cannot be used. But we can make some modification to the buf2Buf() method to copy based on field name instead of field Id.
Below are the two methods:
> global::buf2Buf() - Standard AX method
> THK_buf2BufBySameFileldName() - modified method
//Standard AX method, copy data based on field Id
1)global::buf2Buf
static void buf2Buf(
Common _from,
Common _to
)
{
DictTable dictTable = new DictTable(_from.TableId);
fieldId fieldId = dictTable.fieldNext(0);
while (fieldId && ! isSysId(fieldId))
{
_to.(fieldId) = _from.(fieldId);
fieldId = dictTable.fieldNext(fieldId);
}
}
2)THK_buf2BufBySameFileldName
//Modified method, copy data from one table to another table with similar structure
// USR Changed on 29 十月 2012 at 11:35:14 by admin
static void THK_buf2BufBySameFileldName(Common _from, Common _to)
{
DictTable dictTableFrom = new DictTable(_from.TableId);
DictTable dictTableTo = new DictTable(_to.TableId);
DictField dictFieldFrom;
FieldId fieldIdFrom = dictTableFrom.fieldNext(0);
FieldId fieldIdTo;
;
while (fieldIdFrom && ! isSysId(fieldIdFrom))
{
dictFieldFrom = new DictField(_from.TableId, fieldIdFrom);
if(dictFieldFrom)
{
fieldIdTo = dictTableTo.fieldName2Id(dictFieldFrom.name());
if(fieldIdTo)
_to.(fieldIdTo) = _from.(fieldIdFrom);
}
fieldIdFrom = dictTableFrom.fieldNext(fieldIdFrom);
}
}
2012年10月28日星期日
How to achieve save(put) and get Last Value on Form
1) Use pack/unpack on Form
If you have used runbase classes, you may be impressed by its pack and unpack mechanism. It allows users to keep the input values of last time. If you want to implement the same mechanism on the Form, it is easy as well:
Besides Pack/Unpack, add these six methods:
public class FormRun extends ObjectRun
{
...
#define.CurrentVersion(1)
#localmacro.CurrentList
values...
#endmacro
}
public container pack()
{
return [#CurrentVersion, #CurrentList];
}
public boolean unpack(container packedClass)
{
Integer version = conpeek(packedClass,1);
switch (version)
{
case #CurrentVersion:
[version,#CurrentList] = packedClass;
break;
default:
return false;
}
return true;
}
public dataAreaId lastValueDataAreaId()
{
return curExt();
}
private UserId lastValueUserId()
{
return curuserid();
}
{
return curuserid();
}
private UtilElementType lastValueType()
{
return UtilElementType::Form;
}
{
return UtilElementType::Form;
}
private IdentifierName lastValueElementName()
{
return this.name();
}
{
return this.name();
}
private IdentifierName lastValueDesignName()
{
return ”;
}
//this is called when no last value is retrieved
void initParmDefault()
{
}
further, in Close method of the form:
public void close()
{
super();
//add saveLast method after super()
xSysLastValue::saveLast(this);
}
in init method of the form:
public void init()
{
;
{
return ”;
}
//this is called when no last value is retrieved
void initParmDefault()
{
}
further, in Close method of the form:
public void close()
{
super();
//add saveLast method after super()
xSysLastValue::saveLast(this);
}
in init method of the form:
public void init()
{
;
//Add getLast method before super()
xSysLastValue::getLast(this);
super();
…
}
2)Container lastValues;xSysLastValue::getLast(this);
super();
…
}
get
lastValues = xSyslastValue::getValue(curext(), curUserId(), utilElementType::Form,element.name() + "out","");
put
xSyslastValue::putValue([JournalName],curext(), curUserId(), utilElementType::Form,element.name(),"");
How to using X++ code create and posting a ledger journal
Here is the adapted example for posting a ledger journal line. Simply replace values between #s (#value#):
static void ExampleLedgerJournal(Args _args) { LedgerJournalTable ledgerJournalTable; LedgerJournalTrans ledgerJournalTrans; LedgerJournalCheckPost ledgerJournalCheckPost; NumberSeq numberSeq; ; ttsbegin; // Journal name ledgerJournalTable.JournalName = "#JOURNALNAME#"; // ex. Daily, daytrans, etc. ledgerJournalTable.initFromLedgerJournalName(); ledgerJournalTable.Name = "#DESCRIPTION#"; // description for this journal ledgerJournalTable.insert(); // Voucher numberSeq = NumberSeq::newGetVoucherFromCode(LedgerJournalName::find(ledgerJournalTable.JournalName).VoucherSeries); ledgerJournalTrans.Voucher = numberSeq.voucher(); // Lines ledgerJournalTrans.JournalNum = ledgerJournalTable.JournalNum; ledgerJournalTrans.CurrencyCode = CompanyInfo::standardCurrency(); ledgerJournalTrans.ExchRate = Currency::exchRate(ledgerJournalTrans.CurrencyCode); ledgerJournalTrans.AccountNum = "#ACCOUNT#"; ledgerJournalTrans.AccountType = LedgerJournalACType::Ledger; ledgerJournalTrans.AmountCurDebit = #VALUE#; ledgerJournalTrans.TransDate = systemDateGet(); //Avoid the Today function ledgerJournalTrans.OffsetAccount = "#OFFSET ACCOUNT#"; ledgerJournalTrans.Txt = "#TXT#"; ledgerJournalTrans.insert(); //Posting the Journal ledgerJournalCheckPost = LedgerJournalCheckPost::newLedgerJournalTable(ledgerJournalTable, NoYes::Yes); ledgerJournalCheckPost.run(); ttscommit; }
How to using X++ code to delete AOT nodes
1) TreeNode class
Sometimes, bad objects can not be removed from the AOT because when you click them, Axapta crush !! Look up this job:
Sometimes, bad objects can not be removed from the AOT because when you click them, Axapta crush !! Look up this job:
static void DeleteDamnTables(Args _args) { TreeNode edt, edt2; ; edt = TreeNode::findNode("Data Dictionary\\Tables"); if (edt != null) { edt2 = edt.AOTfindChild("tablename"); if (edt2 != null) edt2.AOTdelete(); } }
2) UtilIdElements solution
Warning: Serious problems might occur if you modify the UtilIdElements table using this or another method. Modify system tables at your own risk. The code:static void Job1(Args _args) { UtilIdElements utilElement; ; ttsbegin; select utilElement where utilElement.name == 'myElementName' && utilElement.utilLevel == utilEntryLevel::cus // any layer && utilElement.recordType == utilElementType::Table; // object type if (utilelement) { utilElement.delete(); ttscommit; info('Record should be deleted now.'); } else { ttsAbort; info('Could not delete record, or it was not found.'); } }
How to invoking to the caller Form/DataSource method
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).
2012年10月19日星期五
How to using SQL statement directly execute to Dynamics AX
This is not a recommended approach to run query against AX, but sometimes there's a need for it (Eg. stored procedure), below is the sample code to run SQL statement directly to the AX database (you'll need to do manual security check due to this approach will skip AX security validation).
I usually has a class with 2 simple method:
- executeUpdate
Used to execute INSERT, UPDATE, DELETE statement - executeQuery
Used to execute SELECT statement
//Class :: SQLUtility ==========================================
class SQLUtility
{
}
//Method :: executeUpdate ======================================
server static int executeUpdate(str sql, Connection connection = new Connection())
{
SqlStatementExecutePermission sqlPerm;
Statement statement;
int rowsAffected;
;
if(sql)
{
sqlPerm = new SqlStatementExecutePermission(sql);
sqlPerm.assert();
statement = connection.createStatement();
rowsAffected = statement.executeUpdate(sql);
CodeAccessPermission::revertAssert();
}
return rowsAffected;
}
//Method :: executeQuery =======================================
server static ResultSet executeQuery(str sql, Connection connection = new Connection())
{
SqlStatementExecutePermission sqlPerm;
Statement statement;
ResultSet resultSet;
;
sqlPerm = new SqlStatementExecutePermission(sql);
sqlPerm.assert();
statement = connection.createStatement();
resultSet = statement.executeQuery(sql);
CodeAccessPermission::revertAssert();
return resultSet;
}
//Job :: Job_DirectSQLTest =====================================
static void Job_DirectSQLTest(Args _args)
{
ResultSet testRS;
;
testRS = SQLUtility::executeQuery("select top 10 ItemId from InventTable");
while(testRS.next())
{
info(testRS.getString(1));
}
}
订阅:
博文 (Atom)