Header Image

Translate

vrijdag 26 juni 2015

Verwijderen van gelijke elementen gedurende Import XPO

 

Bij het importeren van grote XPO bestanden kan het handig zijn om op voorhand al automatisch de elementen te laten controleren waar geen verschil in zit t.o.v. de AOT. De elementen die vervolgens overblijven kunnen dan alsnog handmatig gecontroleerd worden.

De code hiervoor is vrij eenvoudig.

1.) Open de AOT

2.) Ga naar Forms \ SysImportDialog

3.) Voeg onderstaande methode toe aan het form:

1 public void removeDuplicates()
2 {
3 TreeNodePath treeNodePath;
4 TreeNode treenodeInAot;
5 TreeNode treenodeInXpo;
6
7 while select tmpImportAot
8 {
9 try
10 {
11 treeNodePath = tmpImportAot.TreeNodePath;
12 treenodeInAot = TreeNode::findNode(treeNodePath);
13 //AX2012
14 treenodeInXpo = SysImportElementsForm.extractTreenodeFromFile(treeNodePath);
15 //AX2009 - Turn this on for AX2009 and remove line above
16 //treenodeInXpo = SysImportElements.extractTreenodeFromFile(treeNodePath);
17
18 if (treenodeInAot &&
19 treenodeInXpo)
20 {
21 if( SysCompare::silentCompare(SysTreeNode::newTreeNode(treenodeInAot), SysTreeNode::newTreeNode(treenodeInXpo)) )
22 {
23 tmpImportAot.delete();
24 }
25 }
26 }
27 catch
28 {
29 tmpImportAot.delete();
30 continue;
31 }
32 }
33
34 SysImportElementsForm.buildTree(aotTree);
35 SysFormTreeControl::expandTree(aotTree, aotTree.getRoot());
36 }
37

4.) Ga vervolgens naar het Design en open de ButtonGroup AOTButtonGroup.

5.) Voeg een nieuwe button toe: BtnRemoveDuplicateElements

6.) Voeg een Clicked methode toe met onderstaande code


1 void clicked()
2 {
3 super();
4
5 element.removeDuplicates();
6 }

7.) Geef een Label aan de button: Identiek verwijderen.

image

zondag 21 juni 2015

Log de infolog

Het komt geregeld voor dat gebruikers fouten krijgen. Soms duidelijk, soms niet. Soms meld de gebruiker de melding, maar soms ook niet. Voorbeeld:
image
Log de infolog:
image
Het bevat niet de formuliernamen in deze stack, maar wel dat het vanaf een formulier is. Als het via de formletter classes gaat, geeft het al meer inzicht wat de gebruiker aan het doen was. Dit werkt ook in de Ax 4.0 portal: fouten die op de portal gebeuren in de business connector komen ook terug als je de filter goed instelt.

Download

De oplossing voor Ax 2009 (werkt ook voor Ax 4.0), te downloaden hier: INT20150622_AX2009_MessageLog

Inrichting

Na import heb je onder administratie\instellen\Bericht filter/log. Dit opent het scherm:
image
Velden:
Message criteria: Filter met wildcards. ‘*conflict*’ logt alle berichten met het woord conflict erin. ‘*’ gewoon alles
Filter until date: Filter tot datum. Dit is een bewuste implementatie keuze. Het komt tevaak voor dat database logs worden aangezet en dan vergeten. Om te voorkomen dat het systeem zich volvreet met onnodige logging, vul deze datum realistisch.
Filter user: Als je een specifieke gebruiker wil loggen. Leeg = alle
Filter loglevel: De type melding die je wilt loggen. Info, warning error zijn gangbare. Let wel: omdat info een enumwaarde 0 heeft, moet je wel ‘filter loglevel active’ aan hebben staan.
Filter loglevel active: Indien aan, logt het systeem alleen meldingen die voldoen aan je filter loglevel
Created/modified: kan je zien wie de log heeft aangemaakt en gewijzigd.
Voorbeelden:
image
1 – Log alle fouten van iedereen
2 - Log alle warnings van de admin user
3 – Log alle meldingen (info, warning & error) waar de woorden ‘update’ en ‘conflict’ in die volgorde in de tekst staan.

Inhoudelijk

In standaard Ax lopen alle meldingen naar de infolog via dezelfde methode: infoLog.add(…). Daar zit dan ook de enige aanpassing in standaard Ax (naast het menu zelf):
1 Exception add(  2 Exception _exception,  3 str _txt,  4 str _helpUrl = '',  5 SysInfoAction _sysInfoAction = null,   6 boolean buildprefix = true)   7 {   8 // SysInfologLevel infologLevel = this.infologLevel(); 9 int numOfLines,i;  10 int actionClassId; 11 container packedAction; 12 xSession session;  13 ; 14 INTProgramLog::logInfoMessage(_txt, _exception); // INT Ghull - message log 15 switch (logLevel)  16 {  17 case SysInfologLevel::None:  18 return _exception;  19 case SysInfologLevel::Warning:  20 if (_exception == Exception::Info)  21 return _exception;  22 break; 23 case SysInfologLevel::Error:  24 if (_exception == Exception::Info || _exception == Exception::Warning)  25 return _exception;  26 } 27 ....
De security keys zijn gelijk getrokken aan de admin module. Het is net als de database log een tool voor beheerder en consultants om hun werk makkelijker te maken.

image

Let op bij de import. Een aanpassing zoals hier in de info class kan gevaarlijk zijn als deze in een niet-compileerbare staat wordt achtergelaten.

Volgende keer als een gebruiker dus komt: ik krijg een melding zonder de melding nog te weten of dat het sporadisch voorkomt, zet de log aan. Het geeft op zijn minst inzicht in de locatie binnen het programma. Vandaar ook de benaming ‘INTProgramLog’.

Gerrit Hulleman

Databaselog met callstack


Het komt vaak genoeg voor; een log om bepaalde records, velden of acties bij te houden. De database log is hierin een handige tool, maar deze geeft inzicht in onder welk account welke actie met welke waarden zijn gewijzigd, maar niet waar in de applicatie. Soms zijn bijwerkacties niet altijd vanzelfsprekend, en dan is het zoeken naar wat er voor een proces heeft plaatsgevonden. Vooral als de actie plaats vind als onderdeel van een proces in een maatwerk module is het zoeken.
Een kleine aanpassing om te helpen, werkt in AX2009 maar ook AX4.0; toevoegen van de callstack aan de databaselog.
image
Technisch zeer eenvoudig; een nieuw container veld op de sysdatabaselog krijg op moment van de insert de callstack:
1 public void insert()   2 {   3 container callStack; 4 ;   5 6 new SysDatabaseLogPermission().demand();   7 8 this.Username = UserInfoHelp::userName(curuserid()); 9 // INT Ghull - Begin - add calling callstack 10 callStack = xsession::xppCallStack(); 11 callStack = condel(callstack, 1, 6); // Skip the 3 top stack lines {...} 12 this.INTCallStack = callStack;  13 // INT Ghull - end - add calling callstack 14 super();  15 }
Omdat de insert van de databaselog ook op de stack staat, worden de bovenste 6 (3 regels van de callstack maar een callstack container bestaat uit paren van 2 waarden per callstack regel) verwijderd. Dit zijn de xrecord.update(), Application.LogUpdate() en SysDatabaseLog.Insert methoden (of het equivalent bij de insert/delete). Op het SysDatabaseLog form zelf een simpele knop met wel een securitykey om dit in een info te tonen:
1 //INT 20150621 Ghull - show callstack stored in database log 2 void clicked() 3 {   4 int stackLength = conlen(SysDatabaseLog.INTCallStack) / 2; // 2nd value line number 5 int idx; 6 ; 7 8 for (idx = 0; idx < stackLength; idx++)   9 {  10 info(strfmt('%1 (%2)', conpeek(SysDatabaseLog.INTCallStack, idx*2+1),   11 conpeek(SysDatabaseLog.INTCallStack, idx*2+2))); 12 } 13 }
Oplossing voor Ax2009 is te downloaden hier: INT20150622_AX2009_DatabaseLogCallStack.xpo De 4.0 variant is eigenlijk hetzelfde.

Gerrit