Daha önce birkaç AX upgrade projesinde bulundum. Katmanlı mimari malesef upgrade projelerinde çok baş ağrıtıyor. Extensions yaklaşımı ile bu çözülmüş görünüyor.
Size ait olmayan tablo/Data entitylere field/indeks/relation... veya formlara kontrol eklemek istediğinizde direk bir extensions oluşturuyorsunuz:
Enumlar için de aynı şekilde extensions oluşturulurken Enumlarda numara yerine isimden gidilmesi de çok iyi bir çözüm olmuş. Daha önce malesef sistem enumlarında sayısal boşluk bırakmadan eklenen alanlar upgrade esnasında sorun oluyordu. Bu nasıl problem oluyordu:
Mesela bir sistem enum 1-2-3-4-5 diye gidiyor. Bir developer yeni element eklerken 20-30 gibi değer seçmemiş, 6 seçmiş. Microsoft da yeni versiyonda 6'yı ekleyeyim artık demiş. :)
Kod kısmında da yine kolaylıklar var. İlgili nesneyi açıp metodun üzerine gelip sağ mouse ile extensions için gereken şablonu kopyalayabilirsiniz:
Bir class metodundan 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();
...
Bu metodu uygun gördüğünüz bir classa yazıyorsunuz ve artık run metodundan sonra bu metod çalışıyor. Pre-event seçseydik önce çalışacaktı.
Bu örnekte de bir tablonun ondeleted eventını extend ediyoruz:
[DataEventHandler(tableStr(LedgerJournalTable), DataEventType::Deleted)]
public static void LedgerJournalTable_onDeleted(Common sender, DataEventArgs e)
{
LedgerJournalTable ledgerJournalTable = sender as LedgerJournalTable;
...
}
Bir tabloya yeni bir metod eklemek istediğimizde durum biraz değişiyor. Tablonun adı ve _Extension eki içeren bir aşağıdaki gibi class yazıyoruz:
[ExtensionOf(tableStr(ABCRCreditTable))]
final class AGC_ABCRCreditTable_Extension
{
public void updateDefaultDimension()
{
this.DefaultDimension = 11111;
}
}
Veya tablo metodlarından birine ekleme yapmak için yukarıdaki class'a aşağıdaki gibi bir kod yazabilirsiniz. next diğer bağlı metodları çağırmış olursunuz:
void initfromCreditPosting()
{
..... //your codes here
next initfromCreditPosting();
}
Tablo modifiedfield eventına erişim:
[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):
...
LedgerJournalCheckPost validate methoda bir ekleme yapıyoruz:
[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");
}
}
Form lookup metodu override etmek:
[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);
}
Lookup metod içinden form datasource çağırabilmek için aşağıdaki kırmızı işaretli kod gerekiyor:
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();
}
Örnekte formun data source OnInitialized eventında yukarıdaki kodun çalışmasını sağlıyoruz. Bu kod ile datasource içindeki tradenumber fieldının lookup metodunu AGC_CreditTableExt classının lookupTrade metodu ile override ediyoruz. Yukarıdaki metodu istediğiniz bir sınıfa yazabilirsiniz. Ben AGC_CreditTableExt içine yazmayı tercih ettim.
Geçenlerde Peter Ramer'in blogundan CancelSuperCall() metodu ile başka bir lookup extensions yöntemi daha olduğunu öğrendim.
ValidateField örneği:
Tablodaki validateField metodu:
public boolean validateField(FieldId _fieldIdToCheck)
{
CustTable CustTable;
VendTable vendTable;
boolean ret;
ret = super(_fieldIdToCheck);
switch(_fieldIdToCheck)
{
....
....
....
}
}
Classa koyduğumuz validateField extension:
[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);
}
Form metodu post event içinden datasource'a ulaşmak:
[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);
}
Bir forma display metod eklemek:
[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();
}
}