I worked a few AX upgrade projects. Unfortunately multi-layer architect is so painful with upgrade projects. Seem this problem is solved with extensions approach.
When you wanted to add fields/indexes/relations... in tables/data entities or controls in forms you create extensions directly:
Enums doesn't use numbers (at least in development environment) anymore. This's very good for upgrade projects. Unfortunately I lived problems about added elements without any gap to system enums. How it was a problem:
Sample, a system enum goes 1-2-3-4-5 and a developer added a new element. He/she actually should add new element as at least from 20 maybe 30 but added from 6. And in new version Microsoft added 6. :)
In the case of writing code there are some shortcuts. You can open related object and click right mouse for copy template:
A sample class method extension:
[PostHandlerFor(classStr(LedgerJournalCheckPost), methodStr(LedgerJournalCheckPost, run))]
public static void LedgerJournalCheckPost_Post_run(XppPrePostArgs args)
{
LedgerJournalCheckPost post = args.getThis() as LedgerJournalCheckPost;
LedgerJournalTable journalTable;
journalTable = post.parmLedgerJournalTable();
...
}You can put this method in any class and this method will run after run method. If we selected Pre-event, it would be run before run.
In this case we extend ondeleted of a table:
[DataEventHandler(tableStr(LedgerJournalTable), DataEventType::Deleted)]
public static void LedgerJournalTable_onDeleted(Common sender, DataEventArgs e)
{
LedgerJournalTable ledgerJournalTable = sender as LedgerJournalTable;
...
}
If we want to add a new method of a table, things change a bit.
We need a new class named Table name and _Extension word like this:
[ExtensionOf(tableStr(ABCRCreditTable))]
final class AGC_ABCRCreditTable_Extension
{
public void updateDefaultDimension()
{
this.DefaultDimension = 11111;
}
}
Or you can write additional code for a table method below in class up. You call chain methods with next keyword:
void initfromCreditPosting()
{
..... //your codes here
next initfromCreditPosting();
}
Access to
modifiedfield event of a table:
[DataEventHandler(tableStr(ABCRCreditTable), DataEventType::ModifiedField)]
public static void ABCRCreditTable_onModifiedField(Common sender, DataEventArgs e)
{
ABCRCreditTable creditTable = sender as ABCRCreditTable;
ModifyFieldEventArgs eventArgs = e;
int id = eventArgs.parmFieldId();
switch(id)
{
case fieldNum(ABCRCreditTable,CreditAccount):
if (ABCRParameters::find().CRCreditAccountType == ABCRAccountType::Vend)
creditTable.updateDefaultDimension();
break;
case fieldNum(ABCRCreditTable,StrategyNumber):
...
We add extra control on LedgerJournalCheckPost validate method:
[PostHandlerFor(classStr(LedgerJournalCheckPost), methodStr(LedgerJournalCheckPost, validate))]
public static void LedgerJournalCheckPost_Post_validate(XppPrePostArgs args)
{
LedgerJournalCheckPost thisClass = args.getThis();
LedgerJournalTable ledgerJournalTable = thisClass.ledgerJournalTable;
....
....
if (abc)
{
args.setReturnValue(false);
checkfailed("wrong value");
}
}
Override form lookup method:
[FormDataSourceEventHandler(formDataSourceStr(ABCRCreditTable, ABCRCreditTable), FormDataSourceEventType::Initialized)]
public static void ABCRCreditTable_OnInitialized(FormDataSource sender, FormDataSourceEventArgs e)
{
var overrides = new AGC_CreditTableExt();
sender.object(fieldNum(ABCRCreditTable, TradeNumber)).registerOverrideMethod(methodStr(FormDataObject, lookup),
methodStr(AGC_CreditTableExt, lookupTrade), overrides);
}
For call forms datasource from inside Lookup method we need this red highlighted code:
public void lookupStrategyInterCompany(FormControl _formControl)//, str _filterStr)
{
SysTableLookUp sysTableLookUp = SysTableLookup::newParameters(tablenum(AGC_LoanStrategy),_formControl);
Query query = new Query();
QueryBuildDataSource qbds = query.addDataSource(tablenum(AGC_LoanStrategy));
FormObjectSet dataSource = _formControl.formRun().dataSource("ABCRCreditTable");
ABCRCreditTable creditTable = dataSource.cursor();
query.allowCrossCompany(true);
query.addCompanyRange(creditTable.CreditICCompany);
qbds.orderMode(OrderMode::GroupBy);
sysTableLookup.addLookupfield(fieldnum(AGC_LoanStrategy,StrategyNumber));
sysTableLookup.parmQuery(query);
sysTableLookup.performFormLookup();
}
With this sample we make run code at up in forms data source OnInitialized event. We override datasource tradenumber fields lookUp method with AGC_CreditTableExt class lookupTrade method. You can write this code in any class. I choosed AGC_CreditTableExt .
Recently I learned another extension method for override lookups by Peter Ramer's blog by CancelSuperCall() .
ValidateField sample:
ValidateField method in table:
public boolean validateField(FieldId _fieldIdToCheck)
{
CustTable CustTable;
VendTable vendTable;
boolean ret;
ret = super(_fieldIdToCheck);
switch(_fieldIdToCheck)
{
....
....
....
}
}
ValidateField extension which we put in class:
[PostHandlerFor(tableStr(ABCRCreditTable), tableMethodStr(ABCRCreditTable, validateField))]
public static void ABCRCreditTable_Post_validateField(XppPrePostArgs args)
{
ABCRCreditTable creditTable = args.getThis();
FieldId fieldId = args.getArg("_fieldIdToCheck");
boolean ret = args.getReturnValue();
AGC_LoanStrategy strategy;
AGC_LoanTradeComb trade;
switch(fieldId)
{
case fieldNum(ABCRCreditTable, StrategyNumberInterCompany):
if (creditTable.CreditICCompany != "")
{
changecompany(creditTable.CreditICCompany)
{
select firstonly strategy
where strategy.StrategyNumber == creditTable.StrategyNumberInterCompany;
if (strategy.RecId == 0)
{
ret = checkFailed(strFmt("@SCM:TableFieldValidation",
creditTable.StrategyNumberInterCompany,fieldPName(ABCRCreditTable,StrategyNumberInterCompany),
tablePName(ABCRCreditTable)));
}
}
}
break;
}
args.setReturnValue(ret);
}
Access datasource from form method post event:
[PostHandlerFor(formStr(ABCRCreditTable), formMethodStr(ABCRCreditTable, setInterCompanyFields))]
public static void ABCRCreditTable_Post_setInterCompanyFields(XppPrePostArgs args)
{
formrun o = args.getThis();
FormObjectSet ds = o.dataSource("ABCRCreditTable");
ABCRCreditTable creditTable = ds.cursor();
ds.object(fieldNum(ABCRCreditTable,TradeNumberInterCompany)).allowEdit(creditTable.SourceOfLoan
== AGC_SourceOfLoan::Intercompany);
ds.object(fieldNum(ABCRCreditTable,StrategyNumberInterCompany)).allowEdit(creditTable.SourceOfLoan
== AGC_SourceOfLoan::Intercompany);
}
Adding a display method to a form:
[ExtensionOf(formStr(SalesAgreement))]
final class AGC_SalesAgreement_Extension
{
display Amount dispRemainAmount()
{
FormRealControl n = this.design().controlName("NetAmount");
FormRealControl a = this.design().controlName("agreementRemainingRelease");
return n.realValue() * a.realValue();
}
}
Than create a form extension. When added a control compatible with display method (for this sample a real control) datamethod combobox will show this display method.