In questo post segnalo un utile plug in per l'editor Notepad++ per aggiungere tra i linguaggi l'x++.
Il plug è scaricabile da quì:
https://jrabascal.wordpress.com/2014/07/07/creating-user-defined-language-x-into-the-notepad/
Nel link trovate le instruzioni per l'installazione
Ho apportato qualche piccola modifica alle colorazioni delle parole chiavi, l'evidenziazione delle etichette e dei blocchi.
Potete scaricare il file da quì:
https://mega.nz/#!WE9lRY7S!6A-3Wf_vDcEFdFehS5Tikh3pf5cHUzDQfgaPbml0B4w
Questo un esempio:
mercoledì 12 febbraio 2020
giovedì 16 gennaio 2020
AX 2012 - SSRS - Errore su report parameter ‘AX_CompanyName’
Mi è capitato varie volte di imbattermi nel seguente errore quando vado a stampare il primo report dopo il riavvio dei servizi di reporting. L'errore scompare dalla seconda stampa.
"The DefaultValue expression for the report parameter ‘AX_CompanyName’ contains an error: Request for the permission of type 'System.Security.Permissions.EnvironmentPermission, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' failed. (rsRuntimeErrorInExpression)"
L'errore non risulta quindi bloccante ma è piuttosto fastidioso, soprattuto quando capita ad un utente. Quello che posso suggerirvi è di modificare come segue il file rssrvpolicy.config all'interno delle cartelle di SSRS, impostando l'autorizzazione "FullTrust" al posto di "Esegui" per "Report_Expressions_Default_Permissions".
Configurazione iniziale:
<CodeGroup
class="UnionCodeGroup"
version="1"
PermissionSetName="Execution"
Name="Report_Expressions_Default_Permissions"
Description="This code group grants default permissions for code in report expressions and Code element. ">
class="UnionCodeGroup"
version="1"
PermissionSetName="Execution"
Name="Report_Expressions_Default_Permissions"
Description="This code group grants default permissions for code in report expressions and Code element. ">
[...]
</CodeGroup>
Configurazione modificata:
<CodeGroup
class="UnionCodeGroup"
version="1"
PermissionSetName="FullTrust"
Name="Report_Expressions_Default_Permissions"
Description="This code group grants default permissions for code in report expressions and Code element. ">
[..]
</CodeGroup>
Fonte:
https://community.dynamics.com/ax/b/axsupport/archive/2012/02/02/microsoft-dynamics-ax-2012-reporting-extensions-error-system-security-permissions-environmentpermission-while-running-report
AX 2012 - Job Fieldname print
In this post I'll share a job made in order to print an infolog having all the fields of a table in ax with some useful information like, field name, label, help text, data type.
Con questo job invece possiamo stampare il contenuto di una tabella (lista dei campi e valore) in maniera dinamica: static void AGIA_TableFieldNames_2(Args _args)
{
DictTable dt = new SysDictTable(77);
FieldId _fieldId = dt.fieldNext(0);
DictField _dictField;
Dialog dialog;
DialogField myDialogField;
tablename id;
dialog = new dialog();
myDialogField = dialog.addField(extendedTypeStr(tablename), "TableName : ");
dialog.run();
if(dialog.closedOk())
{
id = myDialogField.value();
dt = new sysdicttable(tableName2id(id));
info(strFmt("Field Name; Field Label; Field Type; Field Help; Field Mandatory; Field Lenght"));
if(_fieldId)
while(_fieldId)
{
_dictField =dt.fieldObject(_fieldId);
if(_dictField)
{
if(!_dictField.isSystem())
{
info(strFmt("%1; %2; %3; %4; %5; %6", _dictField.name(),_dictField.label(),_dictField.baseType(),_dictField.help(),_dictField.mandatory(), _dictField.stringLen()));
_fieldId= dt.fieldNext(_fieldId);
}
}
}
else
{
info(strFmt("Missing table %1", id));
}
}
}
static void LIL_PrintTableValue(Args _args)
{
DictTable dt;
DictField dictField;
Common common;
Counter i=0;
FieldId fieldId;
dt = new DictTable(tableNum(InventSite));
common = dt.makeRecord();
while select common
{
fieldId = dt.fieldNext(0);
while (fieldId)
{
dictField = dt.fieldObject(fieldId);
if(dictField.configurationKeyId() != configurationkeynum(SysDeletedObjects60))
{
info(strFmt("%1 = %2",fieldId2name(dt.id(),dictField.id()),common.(dictField.id())));
}
fieldId = dt.fieldNext(fieldId);
}
info("---------------------");
}
}
mercoledì 26 giugno 2019
AX 2012 - Job per creazione progetto da CSV
In questo post pubblico un job che ho scritto che serve per creare un progetto privato leggendo un csv contenente una lista di tipi e nomi degli elementi dell'AOT
L'output sarà il seguente:
static void LIL_ProjectElementAdd(Args _args)
{
TextIo inFile;
container line;
Counter records;
SysOperationProgress simpleProgress;
container fileContainer;
Counter loopCounter;
CustTable CustTable;
InventTable InventTable;
str filename,
properties,
objectType,
objectName,
aotType,aotPath;
TreeNode projectNode,
tempNode;
ProjectGroupNode groupNode;
boolean managed;
#OCCRetryCount
#AviFiles
#File
#aot
#DMF
filename = WinAPI::getOpenFileName(0,
[WinAPI::fileType(#csv),#AllFilesName + #csv],
strFmt(@'C:\users\%1\Desktop',WinApi::getUserName()),
"@SYS53008"
);
try
{
inFile = new TextIo(filename, 'r');
inFile.inRecordDelimiter('\n');
inFile.inFieldDelimiter(';');
while (inFile.status() == IO_Status::OK)
{
fileContainer += [infile.read()];
}
inFile = null;
}
catch
{
throw error(strFmt("@SYS18678", filename));
}
simpleProgress = SysOperationProgress::newGeneral(#aviUpdate, "Importazione...", conLen(fileContainer));
records = 0;
projectNode = SysTreeNode::createProject("MyPrivateProject");
groupNode = projectNode.AOTadd("Object");
properties = groupNode.AOTgetProperties();
for (loopCounter = 2; loopCounter <= conLen(fileContainer) - 1 ; loopCounter++)
{
line = conPeek(fileContainer,loopCounter);
objectType = conPeek(line,1);
objectName = conPeek(line,2);
switch(objectType)
{
case "BaseEnum" :
aotType = #BaseEnums;
aotPath = #BaseEnumsPath;
managed = true;
break;
case "Class" :
aotType = #Classes;
aotPath = #ClassesPath;
managed = true;
break;
case "ExtendedDataType" :
aotType = #ExtendedDataTypes;
aotPath = #ExtendedDataTypesPath;
managed = true;
break;
case "Form" :
aotType = "Forms";
aotPath = #FormsPath;
managed = true;
break;
case "Macro" :
aotType = "Macros";
aotPath = #MacrosPath;
managed = true;
break;
case "Menu" :
aotType = "Menus";
aotPath = #MenusPath;
managed = true;
break;
case "Table" :
aotType = "Tables";
aotPath = #TablesPath;
managed = true;
break;
case "Map" :
aotType = "Maps";
aotPath = #TableMapsPath;
managed = true;
break;
case "Query" :
aotType = #Queries;
aotPath = #QueriesPath;
managed = true;
break;
case "SecurityDuty" :
aotType = "SecDuties";
aotPath = #SecDutiesPath;
managed = true;
break;
case "SecurityPrivilege" :
aotType = "SecPrivileges";
aotPath = #SecPrivilegesPath;
managed = true;
break;
case "SecurityPrivilege" :
aotType = "SecPrivileges";
aotPath = #SecPrivilegesPath;
managed = true;
break;
case "SecurityProcessCycle" :
aotType = "SecProcessCycles";
aotPath = #SecProcessCyclesPath;
managed = true;
break;
case "SecurityRole" :
aotType = "SecRoles";
aotPath = #SecRolesPath;
managed = true;
break;
case "SSRSReport" :
aotType = "SSRSReports";
aotPath = #SSRSReportsPath;
managed = true;
break;
case "VisualStudioProjectCSharp" :
aotType = "VSProjectsCShar";
aotPath = #VSProjectsCSharpPath;
managed = true;
break;
default:
managed = false;
warning(strFmt("Unable to add %1, %2",objectType,objectName));
}
if(objectName && managed)
{
tempNode = TreeNode::findNode(aotPath);
groupNode.addNode(tempNode.AOTfindChild(objectName));
}
}
projectNode.AOTsave();
}
L'output sarà il seguente:
martedì 11 giugno 2019
AX 2012 - Job dimensioni finanziarie
In questo post vediamo due job per manipolare le dimensione finanziarie ed assegnare il risultato ad una riga di general journal
il secondo crea una ledger dimension contente solamente il bank account num:
Il primo job, data una ledger dimension cambia l'account e valida la nuova dimensione:
static void LIL_ChangeAccountNum(Args _args)
{
LedgerJournalTrans ledgerJournalTrans;
DimensionDefault dimensiondefault;
LedgerDimensionAccount LedgerDimensionAccount, ret;
DimensionValidationStatus status;
MainAccountNum newMainAccountnum = "10505005";
ledgerJournalTrans = ledgerJournalTrans::findRecId(5644985326, false);
dimensiondefault = DimensionDefaultingEngine::getDefaultDimension(DimensionDefaultingEngine::getDimensionSourcesForLedgerDimension(ledgerJournalTrans.ledgerdimension));
LedgerDimensionAccount = AxdDimensionUtil::getLedgerAccountId([newMainAccountnum,newMainAccountnum]);
ret = DimensionDefaultingService::serviceCreateLedgerDimension(LedgerDimensionAccount,dimensiondefault);
status = DimensionValidation::validateByTree(ret,today(),true);
if(status == DimensionValidationStatus::Valid)
{
ledgerJournalTrans.LedgerDimension = ret;
}
}
il secondo crea una ledger dimension contente solamente il bank account num:
static void LIL_LedgerDimensionWhitAccountOnly(Args _args)
{
LedgerJournalTrans ledgerJournalTrans;
DimensionDynamicAccount DimensionDynamicAccount;
DimensionDynamicAccount = DimensionStorage::getDynamicAccount("BANK001", LedgerJournalACType::Bank);
ledgerJournalTrans.LedgerDimension = DimensionDynamicAccount;
}
mercoledì 5 giugno 2019
D365 - Script for checking the code executed while inserting data in a table manually
In order to have a quick list of fields inserted in a form we can proceed in the following way.
First insert a record in the table we want to analyse.
At this point access the following button Option --> Record info.
First insert a record in the table we want to analyse.
At this point access the following button Option --> Record info.
Click on the button Script as reported below.
The following txt document is created, in which the procedures for inserting a row in the table previously filled manually are retrieved.
lunedì 20 maggio 2019
AX 2012 - Creare batch job tramite x++ e aggiunta dipendenze
In questo post vediamo come creare dei batch job schedulabili e suddividere l'esecuzione in task. Sfruttando inoltre le "Batch Dependency" faremo in modo che ogni task parta solo se il precedente termina ( oppure và in errore ). Allo scopo creiamo una semplice classe sysoperation (LIL_WhoAmIService più relativa controller / contract) che prende come parametro un intero e lo restiuisce tramite info log. Il job seguente effettua tutte le operazioni di schedulazione / aggiunta dipendenze:
Se lanciamo il job ed aspettiamo la fine dell'esecuzione dei 10 task, possiamo vedere il risultato in batch history:
L'esecuzione ha generato 10 tasks. il Task "N0" come vediamo non ha condizioni. Tutti gli altri dipendono dal precedente, Ad esempio il task N5 dipende dal task N4 e così via.
static void LIL_TestRunDependency(Args _args)
{
BatchHeader batchHeader = BatchHeader::getCurrentBatchHeader();
List list = new List(Types::Class);
ListEnumerator le;
LIL_WhoAmIController batchTask,prev;
Counter i;
BatchInfo batchInfo;
batchHeader = batchHeader::construct();
batchHeader.parmCaption("Task dependency execution");
//creo 10 instaze della mia classe, ciascuna con il suo id
for(i = 0; i < 10; i++)
{
batchTask = new LIL_WhoAmIController(classStr(LIL_WhoAmIService),
methodStr(LIL_WhoAmIService, printWhoAmi));
batchTask.parmWhoAmi(i);
batchTask.init();
//in caso di sysoperation è neccessario impostare execution mode = Synchronous
//altrimenti le dipendence non vengono rispettate e i task partono tutti
//allo stesso momento
batchTask.parmExecutionMode(SysOperationExecutionMode::Synchronous);
batchInfo = batchTask.batchInfo();
batchInfo.parmCaption(strFmt("Task N%1",batchTask.parmWhoAmi(i)));
list.addStart(batchTask);
}
//Creazione dipendenze
le = list.getEnumerator();
while (le.moveNext())
{
batchTask = le.current();
if(!prev)
{
//il primo task non avarà voncoli
batchHeader.addRuntimeTask(batchTask,BatchHeader::getCurrentBatchTask().RecId);
}
else
{
//i successivi dipendono dal precedente
batchHeader.addRuntimeTask(batchTask,BatchHeader::getCurrentBatchTask().RecId);
batchHeader.addDependency(prev,batchTask,BatchDependencyStatus::FinishedOrError);
}
prev = le.current();
}
batchHeader.save();
info("Done");
}
Se lanciamo il job ed aspettiamo la fine dell'esecuzione dei 10 task, possiamo vedere il risultato in batch history:
L'esecuzione ha generato 10 tasks. il Task "N0" come vediamo non ha condizioni. Tutti gli altri dipendono dal precedente, Ad esempio il task N5 dipende dal task N4 e così via.
Iscriviti a:
Post (Atom)


