Hola.
Cuando por alguna situación requerimos escribir código para el evento "onLookup" de un control en un formulario de Dynamics 365 FO, nos encontramos que al ejecutarlo se muestra el mensaje "More Than One Form Was Opened at Once for the Lookup Control"
Captura de ejemplo:
Para solucionarlo, sigue los siguientes pasos:
1. Declara una nueva variable del tipo "FormControlCancelableSuperEventArgs"
2. Inicializa la variable con el valor FormControlEventArgs del parámetro "e"
3. Usa la variable para llamar al método CancelSuperCall()
Ejemplo:
Enjoy daXing
Thursday, February 21, 2019
Wednesday, December 19, 2018
Extension de una Tabla en Dynamics 365 Finance and Operations
Una de las novedades que más impacto puede traer a la hora de querer agregar funcionalidad a objetos nativos de Ax es que se recomienda NO tocar los Originales (Overlaying) y en vez de esto, crear un extensión del mismo y ahí hacer las modificaciones pertinentes.
Esto tiene una ventaja enorme, significa mantener los objetos intactos y cuando Microsoft haga alguna actualización pues no tocará nada de lo que hayamos desarrollado afectando únicamente al estándar de Ax.
Vamos a la práctica.
Supongamos que tenemos una tabla con cierto número de campos y queremos agregar algún otro campo que haga falta sin afectar a la tabla original.
Vamos a crear una nueva Tabla (en la vida real, esta sería una tabla nativa de Ax)
Le agregamos los campos base:
Ahora vamos a crear una extensión de la tabla (Buscamos nuestra tabla desde el AOT, si no se encuentra, debemos sincronizar primero el proyecto con la base de datos)
Esto agrega un nuevo objeto a nuestro proyecto con el Nombre del objeto original y agregando .Extensión
Lo abrimos y le agregamos un nuevo campo:
Sincronizamos nuevamente y ahora vamos a escribir algo de código. La idea es instanciar un objeto de la tabla original (MyTable) que a su vez, al tener una extensión, debería mostrarnos tres campos (dos originales y uno de la extensión)
El job, agrega un nuevo registro. Para comprobar la funcionalidad, visualizamos la tabla en el explorador:
Como podemos ver, la tabla tiene tres campos, y no dos como originalmente estaba diseñada.
Espero haberles ayudado.
Saludos!
Esto tiene una ventaja enorme, significa mantener los objetos intactos y cuando Microsoft haga alguna actualización pues no tocará nada de lo que hayamos desarrollado afectando únicamente al estándar de Ax.
Vamos a la práctica.
Supongamos que tenemos una tabla con cierto número de campos y queremos agregar algún otro campo que haga falta sin afectar a la tabla original.
Vamos a crear una nueva Tabla (en la vida real, esta sería una tabla nativa de Ax)
| Clic derecho sobre el proyecto, Add y finalmente New ítem.. |
| En la sección Data Model, tenemos la opción Table. Le damos un nombre y agregamos |
Le agregamos los campos base:
| Los campos se agregan de manera tradicional; click derecho, New, tipo de dato deseado... |
Ahora vamos a crear una extensión de la tabla (Buscamos nuestra tabla desde el AOT, si no se encuentra, debemos sincronizar primero el proyecto con la base de datos)
| Sobre el AOT, se puede hacer una búsqueda para encontrar nuestro objeto al cual le crearemos un "Extensión" |
| Extensión del Objeto |
Lo abrimos y le agregamos un nuevo campo:
| Abrir el objeto Extension |
| Se agrega el nuevo campo |
| La instancia del Objeto MyTable muestra el campo creado en la Extension |
El job, agrega un nuevo registro. Para comprobar la funcionalidad, visualizamos la tabla en el explorador:
| Para visualizar los datos de la tabla en un Web Browser |
| Vista previa de la tabla con los tres campos y sus datos respectivamente. |
Como podemos ver, la tabla tiene tres campos, y no dos como originalmente estaba diseñada.
Espero haberles ayudado.
Saludos!
Tuesday, December 18, 2018
Ejecutando un JOB en Dynamics 365 Finance and Operations
En Dynamics 365 todo es diferente.
Veamos como ejecutar un Job con un poco de código sencillo
Primero creamos el Proyecto:
Configuramos el Model y la opción para que se sincronice automáticamente al hacer "Build"
Agregamos una "Runnable class"
Agregamos algo de código
Establecemos la clase como objeto de inicio (Set as StartUp Object)
Y ahí tenemos el resultado!
:)
Saludos
Veamos como ejecutar un Job con un poco de código sencillo
Primero creamos el Proyecto:
Agregamos algo de código
Establecemos la clase como objeto de inicio (Set as StartUp Object)
Finalmente ejecutamos el proyecto (F5)
Y ahí tenemos el resultado!
:)
Saludos
Wednesday, November 29, 2017
Max number of sessions in WHS Dynamcs Ax 2012 R3
When we implemented a WHS module in Dynamics Ax 2012 R3, we experimented
some issues but the most stressfull issue was the WHS web service crashed with five
or six concurrent users.
I tought it was a configuration parameter about limit of
conecctions, but i didnt know wich parameter, maybe an IIS parameter or AIF
parámeter, was the second.
First of all, we have to select the follow menú: System
Administration/ Setup / Services and Application Integration Framework/ EndPoints
In the endpoints form we are going to filter the whs* as the
follow image show

We are going to desactivate the endpoint and then we clic
the setup button and then, if we don’t have the right software tool to edit the
file, the notepad Will open the file.
The netTCPBinding node has a maxConnections parameter but it was
useless in this scenario.
But ServiceThrotting parameter had the solution, we had 200
in values of maxCurrentCalls, maxCurrentInstances, maxCurrentSessions

So, each users made several petitions to the service, even a
user who refreshed the webpage repeatly
Just we increased the value of each parameter and we notice
the website was supported more users tan before.
It really works for us!
See you!
Labels:
200,
AIF,
AX,
Dynamics Ax 2012 R3,
netTCPBinding,
ServiceThrotting,
Web Service,
WHS,
WMS,
X++
Tuesday, November 28, 2017
Saving a Dynamics Ax Report to PDF
Hi guys!
I am gonna show you how to save a Dynamics Ax Report to PDF file.
We are going to use de getTempPath() method from WinApi class for getting the tmp directory.
static void saveProdId()
{
ReportRun report;
Args args;
ProdBOM prodBOM;
FilePath path;
ProdId prodId;
;
path = WinAPI::getTempPath();
prodId= 'ProdIdNumber';
select prodBOM where prodBOM.ProdId == prodId
&& prodBOM.ProdLineType == BomType::Vendor;
args = new Args();
args.name(reportStr(SomeReport));
args.record(prodBOM);
report = ClassFactory.reportRunClass(args);
report.printJobSettings().setTarget(PrintMedium::File);
report.printJobSettings().preferredTarget(PrintMedium::File);
report.printJobSettings().format(PrintFormat::PDF);
report.printJobSettings().fileName(path + prodId + '.pdf');
report.query().interactive(false);
report.run();
}
See you!
I am gonna show you how to save a Dynamics Ax Report to PDF file.
We are going to use de getTempPath() method from WinApi class for getting the tmp directory.
static void saveProdId()
{
ReportRun report;
Args args;
ProdBOM prodBOM;
FilePath path;
ProdId prodId;
;
path = WinAPI::getTempPath();
prodId= 'ProdIdNumber';
select prodBOM where prodBOM.ProdId == prodId
&& prodBOM.ProdLineType == BomType::Vendor;
args = new Args();
args.name(reportStr(SomeReport));
args.record(prodBOM);
report = ClassFactory.reportRunClass(args);
report.printJobSettings().setTarget(PrintMedium::File);
report.printJobSettings().preferredTarget(PrintMedium::File);
report.printJobSettings().format(PrintFormat::PDF);
report.printJobSettings().fileName(path + prodId + '.pdf');
report.query().interactive(false);
report.run();
}
See you!
Labels:
Dynamics Ax 2012 R3,
getTempPath,
getTempPath(),
PDF,
printJobSettings,
Report,
WinApi,
X++
Monday, November 13, 2017
Using Infolog Ax 2012 R3
In this post you can learn how to use InfoLog class for sending a beautiful and professional messages in Dynamics Ax, however final user could not notice your effort.
static void testJCAinfo(Args _args)
{
SetPrefix("Grandpa");
SetPrefix("Dad");
SetPrefix("Me");
Infolog.add(Exception::Warning,"Puppy");
}
And the result is:
static void testJCAinfo(Args _args)
{
SetPrefix("Grandpa");
SetPrefix("Dad");
SetPrefix("Me");
Infolog.add(Exception::Warning,"Puppy");
}
And the result is:
Now you have the power to agroup the info messages in Ax, but you can give more functionally if you want. check the code below
static void Test(Args _args)
{
SysInfoAction_FormRun infoAction = SysInfoAction_FormRun::newFormName(formStr(EcoResProductDetailsExtended)); //Which form?
infoAction.parmCallerBuffer(InventTable::find('TEST5')); // which record??
Infolog.add(Exception::Warning,"El artículo no está propiamente configurado",'',infoAction);
}
First, we got the itemid with errors (TEST5)
In the message infolog we select the message
Notice a new button is appear automatically, and if you click on it, Ax shows you the EcoResProductDetailsExtended with the TEST5 Item.
Wednesday, November 1, 2017
Using RoundUp and RoundDown
Sometimes we would need to round a number, in this case you can use global method roundUp or rounDown.
static void roundExample()
{
info(num2expstr(roundUp(6.5 ,1)));
}
The result is 7,
This morning I was in trouble using this function... the result was 6 instead 7 such as if I would using roundDown, some minutes later I notice I was tryng rounding a negative number LOL.
Thursday, October 19, 2017
Creating a purchPackingSlip from Code X++
Hi there!
In this code i'm showing you how to create a purch packing slip from code...
private void createPackingSlip(PurchId _purchId,packingSlipId _packingSlipId, Qty _qtyToReceive)
{
PurchFormLetter purchFormLetter;
PurchFormletterParmData purchFormLetterParmData;
PurchParmUpdate purchParmUpdate;
PurchParmTable purchParmTable;
PurchParmLine purchParmLine;
PurchTable purchTable;
PurchLine purchLine;
PurchId purchId;
Num packingSlipId;
Qty qtyToReceive;
purchId = _purchId;
packingSlipId = _packingSlipId;
purchTable = PurchTable::find(purchId);
qtyToReceive = _qtyToReceive;
ttsBegin;
// Create PurchParamUpdate table
purchFormLetterParmData = PurchFormletterParmData::newData(
DocumentStatus::PackingSlip,
VersioningUpdateType::Initial);
purchFormLetterParmData.parmOnlyCreateParmUpdate(true);
purchFormLetterParmData.createData(false);
purchParmUpdate = purchFormLetterParmData.parmParmUpdate();
// Set PurchParmTable table
purchParmTable.clear();
purchParmTable.TransDate = SystemDateGet();
purchParmTable.Ordering = DocumentStatus::PackingSlip;
purchParmTable.ParmJobStatus = ParmJobStatus::Waiting;
purchParmTable.Num = packingSlipId;
purchParmTable.PurchId = purchTable.PurchId;
purchParmTable.PurchName = purchTable.PurchName;
purchParmTable.DeliveryName = purchTable.DeliveryName;
purchParmTable.DeliveryPostalAddress = purchTable.DeliveryPostalAddress;
purchParmTable.OrderAccount = purchTable.OrderAccount;
purchParmTable.CurrencyCode = purchTable.CurrencyCode;
purchParmTable.InvoiceAccount = purchTable.InvoiceAccount;
purchParmTable.ParmId = purchParmUpdate.ParmId;
purchParmTable.insert();
// Set PurchParmLine table
select purchLine
where purchLine.PurchId == _purchId;
purchParmLine.InitFromPurchLine(purchLine);
purchParmLine.ReceiveNow = _qtyToReceive;
purchParmLine.ParmId = purchParmTable.ParmId;
purchParmLine.TableRefId = purchParmTable.TableRefId;
purchParmLine.setQty(DocumentStatus::PackingSlip, false, true);
purchParmLine.setLineAmount();
purchParmLine.insert();
purchFormLetter = PurchFormLetter::construct(DocumentStatus::PackingSlip);
purchFormLetter.transDate(systemDateGet());
purchFormLetter.proforma(false);
purchFormLetter.specQty(PurchUpdate::All);
purchFormLetter.purchTable(purchTable);
purchFormLetter.parmParmTableNum(purchParmTable.ParmId);
purchFormLetter.parmId(purchParmTable.ParmId);
purchFormLetter.purchParmUpdate(purchFormLetterParmData.parmParmUpdate());
purchFormLetter.run();
ttsCommit;
}
I hope this will be useful.
Labels:
AX2012,
Dynamics Ax 2012 R3,
PackingSlipId,
X++
Thursday, January 7, 2016
Validating user domain password in Ax 2012 (AxaptaUserManager)
Hi there!
I think it is time to let you know how you can validate the user domain password in Ax 2012 R3, also it works on Ax 2009.
We need to create an instance of AxaptaUserManager... let's codify
01 static void JC(Args _args)
02 {
03
04 AxaptaUserManager axUserManager;
05 UserInfo userInfo;
06 ;
07
08 userInfo = xUserInfo::find(false, curuserId());
09
10 axUserManager = new AxaptaUserManager();
11
12 if (axUserManager.validatePassword(userInfo.networkAlias , userInfo.NetworkDomain, "4V3rYC0mpl3xPa$$w0rd!!"))
13 {
14 info ("Welcome to the jungle!!!");
15 }
16 else
17 {
18 info ("Intruder");
19 }
20
21}
In the line number 12, the last parameter of the code is a very complex password of the user of the first parameter in the domain specified in the second parameter, return true if the password is correct!
I do not want to insult your intelligence, so I do not profundize on the topic, LOL
I think it is time to let you know how you can validate the user domain password in Ax 2012 R3, also it works on Ax 2009.
We need to create an instance of AxaptaUserManager... let's codify
01 static void JC(Args _args)
02 {
03
04 AxaptaUserManager axUserManager;
05 UserInfo userInfo;
06 ;
07
08 userInfo = xUserInfo::find(false, curuserId());
09
10 axUserManager = new AxaptaUserManager();
11
12 if (axUserManager.validatePassword(userInfo.networkAlias , userInfo.NetworkDomain, "4V3rYC0mpl3xPa$$w0rd!!"))
13 {
14 info ("Welcome to the jungle!!!");
15 }
16 else
17 {
18 info ("Intruder");
19 }
20
21}
In the line number 12, the last parameter of the code is a very complex password of the user of the first parameter in the domain specified in the second parameter, return true if the password is correct!
I do not want to insult your intelligence, so I do not profundize on the topic, LOL
Labels:
Ax2009,
AX2012,
AxaptaUserManager,
Dynamics Ax 2012 R3
Tuesday, November 24, 2015
Creating a CSV File from Ax
Hi!
Now I am about to show you how create a CSV file in Ax 2012 R3.
First of all, we need to create an instance of the class CommaTextIo, a Container, and the reference to the #File macro.
01 static void CreateCSV(Args _args)
02 {
03 CommaTextIo file;
04 Container line;
05 InventTable inventTable;
06 #File
07
08 file = new CommaTextIo("c:\\users\\jarizmendi\\aCSVFile.csv", #io_write);
09 if (!file || file.status() != IO_Status::Ok)
10 {
11 throw error("File cannot be opened.");
12 }
13
14 while select * from inventTable
15 {
16 line = [inventTable.ItemId, inventTable.ItemName];
17 file.writeExp(line);
18 }
19 info("It works!!.");
20 }
Then, we need to create the CSV file in a specified directory, and finally, we need to write the data as lines 14 to 18 show.
I hope it helps!!
Now I am about to show you how create a CSV file in Ax 2012 R3.
First of all, we need to create an instance of the class CommaTextIo, a Container, and the reference to the #File macro.
01 static void CreateCSV(Args _args)
02 {
03 CommaTextIo file;
04 Container line;
05 InventTable inventTable;
06 #File
07
08 file = new CommaTextIo("c:\\users\\jarizmendi\\aCSVFile.csv", #io_write);
09 if (!file || file.status() != IO_Status::Ok)
10 {
11 throw error("File cannot be opened.");
12 }
13
14 while select * from inventTable
15 {
16 line = [inventTable.ItemId, inventTable.ItemName];
17 file.writeExp(line);
18 }
19 info("It works!!.");
20 }
Then, we need to create the CSV file in a specified directory, and finally, we need to write the data as lines 14 to 18 show.
I hope it helps!!
Labels:
AX2012,
CommaTextIo,
Dynamics Ax 2012 R3,
X++
Friday, November 20, 2015
Updating Inventory Dimensions Group in Ax 2012
Hi!
If you need to change the Inventory Dimension Groups In Ax (StorageDimensionGroup and TrackingDimensionGroup), you could use this.
1 InventTable inventTable;
2 EcoResStorageDimensionGroup ecoResStorageDimensionGroup;
3 EcoResTrackingDimensionGroup ecoResTrackingDimensionGroup;
4 ;
5 inventTable = InventTable::find("anArticle");
6 ecoResStorageDimensionGroup = ecoResStorageDimensionGroup::findByDimensionGroupName("anotherGroup");
7 ecoResTrackingDimensionGroup = ecoResTrackingDimensionGroup::findByDimensionGroupName("anotherGroup");
8
9 InventTableInventoryDimensionGroups::updateDimensionGroupsForItem(
10 curext()
11 , inventTable.ItemId
12 , ecoResStorageDimensionGroup.RecId
13 , ecoResTrackingDimensionGroup.RecId
14 , inventTable.Product);
15 }
Line 1 to 4 declarations, line 5 to 7 finding the ItemId named "AnArticle" and the Storage Dimension Group and the Tracking Dimension Group, they both named "anotherGroup".
Line 9 performs the updateDimensionGroupsForItem of the class InventTableInventoryDimensionGroups.
Important!. There must not be physical movementsor financial movements pending for this item.
If you need to change the Inventory Dimension Groups In Ax (StorageDimensionGroup and TrackingDimensionGroup), you could use this.
1 InventTable inventTable;
2 EcoResStorageDimensionGroup ecoResStorageDimensionGroup;
3 EcoResTrackingDimensionGroup ecoResTrackingDimensionGroup;
4 ;
5 inventTable = InventTable::find("anArticle");
6 ecoResStorageDimensionGroup = ecoResStorageDimensionGroup::findByDimensionGroupName("anotherGroup");
7 ecoResTrackingDimensionGroup = ecoResTrackingDimensionGroup::findByDimensionGroupName("anotherGroup");
8
9 InventTableInventoryDimensionGroups::updateDimensionGroupsForItem(
10 curext()
11 , inventTable.ItemId
12 , ecoResStorageDimensionGroup.RecId
13 , ecoResTrackingDimensionGroup.RecId
14 , inventTable.Product);
15 }
Line 1 to 4 declarations, line 5 to 7 finding the ItemId named "AnArticle" and the Storage Dimension Group and the Tracking Dimension Group, they both named "anotherGroup".
Line 9 performs the updateDimensionGroupsForItem of the class InventTableInventoryDimensionGroups.
Important!. There must not be physical movementsor financial movements pending for this item.
Labels:
Dynamics Ax 2012 R3,
InventTableInventoryDimensionGroups,
Storage,
StorageDimensionGroup,
Tracking.,
TrackingDimensionGroup,
X++
Monday, July 27, 2015
Using SysLastValue in Ax 2012 R3
We can save some prompt values in forms without using a table, in this post I will show you how you can use SystemLastValue.
1. Design a form (jcSysLastValue) with an editable field, in this case I used am ImventLocationId field.
2. We have to edit the classDeclaration as follows:
public class FormRun extends ObjectRun
{
InventLocationId inventLocationId;
InventLocationId inventLocationId2;
#define.CurrentVersion(1)
#define.version1(1)
#localmacro.CurrentList
inventLocationId,
inventLocationId2
#endmacro
}
{
InventLocationId inventLocationId;
InventLocationId inventLocationId2;
#define.CurrentVersion(1)
#define.version1(1)
#localmacro.CurrentList
inventLocationId,
inventLocationId2
#endmacro
}
3. Write the method initParmDefault() to set a default Value
public void initParmDefault()
{
;
inventLocationId = "001";
}
4. Define the methods pack and unPack()
public container pack()
{
return [#CurrentVersion,#CurrentList];
}
public boolean unpack(container packedClass)
{
int version = RunBase::getVersion(packedClass);
switch (version)
{
case #CurrentVersion:
[version,#CurrentList] = packedClass;
return true;
default :
return false;
}
return false;
}
5. Define the methods lastValue....
public dataAreaId lastValueDataAreaId()
{
return curext();
}
public identifiername lastValueDesignName()
{
return '';
}
public identifiername lastValueElementName()
{
return formStr(jcSysLastValue);
}
public UtilElementType lastValueType()
{
return UtilElementType::Form;
}
public userId lastValueUserId()
{
return curuserid();
}
6. Getting saved values and setting them to the field.
public void run()
{
super();
xSysLastValue::getLast(this);
inventLocationId_text.text(inventLocationId);
}
7. Saving values to somewhere
public void close()
{
super();
inventLocationId = inventLocationId_text.text();
xSysLastValue::saveLast(this);
}
If you want to clear the values just delete de follow record and that's it.
Subscribe to:
Posts (Atom)





