lunes, 4 de junio de 2012

Enviar mail mediante codigo X++

Hola, este es el fragmento de codigo que sirve para poder enviar correos electrónicos mediante Dynamics AX (probado en version ax 2009)

SysEmailParameters sysEmailParameters = SysEmailParameters::find();
InteropPermission  interopPermission;
SysMailer            sysMailer;
;
 
//Inicialización de los parámetros de correo electrónico.
interopPermission = new InteropPermission(InteropKind::ComInterop);
interopPermission.assert();
sysMailer = new SysMailer();
 
if(sysEmailParameters.smtpRelayServerName)
{
 sysMailer.SMTPRelayServer(sysEmailParameters.smtpRelayServerName,
 sysEmailParameters.smtpPortNumber,
 sysEmailParameters.smtpUserName,
 SysEmailParameters::password(),
 sysEmailParameters.ntlm);
}
else
{
 sysMailer.SMTPRelayServer(sysEmailParameters.smtpServerIPAddress,
 sysEmailParameters.smtpPortNumber,
 sysEmailParameters.smtpUserName,
 SysEmailParameters::password(),
 sysEmailParameters.ntlm);
}
 
//Escribimos el Mail
sysMailer.htmlBody("Mensaje de prueba :)");
sysMailer.subject("Test 1");
sysMailer.fromAddress("dirección mail origen");
sysMailer.tos().appendAddress("dirección mail destino");
 
//Si queremos documento adjunto
sysMailer.attachments().add("Ruta y nombre dle fichero adjunto");
 
sysMailer.sendMail();

Si tuvieramos algún problema al momento de ejecutar el envío del mail, el error generalmente es por algo que ha ocurrido en la clase 'CDO.Message'.
El sistema mostrara un aviso de error parecido a este:
Method 'send' in COM object of class 'CDO.Message' returned error code 0x800...

Les dejo una lista de lo que significa cada posible codigo que les pudiera salir:

0x80040201Exception %1 was generated at address %2.
0x80040202
No data source has been opened for the object.
0x80040203
The object does not support this type of data source.
0x80040204
The object does not support the requested property name or namespace.
0x80040205
The object does not support the requested property.
0x80040206
The object is not active. It may have been deleted or it may not have been opened.
0x80040207
The object does not support storing persistent state information for objects.
0x80040208
The requested property or feature, while supported, is not available at this time or in this context.
0x80040209
No default drop directory has been configured for this server.
0x8004020A
The SMTP server name is required, and was not found in the configuration source.
0x8004020B
The NNTP server name is required, and was not found in the configuration source.
0x8004020C
At least one recipient is required, but none were found.
0x8004020D
At least one of the From or Sender fields is required, and neither was found.
0x8004020E
The server rejected the sender address. The server response was: %1
0x8004020F
The server rejected one or more recipient addresses. The server response was: %1
0x80040210
The message could not be posted to the NNTP server. The transport error code was %2. The server response was %1
0x80040211
The message could not be sent to the SMTP server. The transport error code was %2. The server response was %1
0x80040212
The transport lost its connection to the server.
0x80040213
The transport failed to connect to the server.
0x80040214
The Subject, From, and Newsgroup fields are all required, and one or more was not found.
0x80040215
The server rejected the logon attempt due to authentication failure. The server response was: %1
0x80040216
The content type was not valid in this context. For example, the root of an MHTML message must be an HTML document.
0x80040217
The transport was unable to log on to the server.
0x80040218
The requested resource could not be found. The server response was: %1.
0x80040219
Access to the requested resource is denied. The server response was: %1.
0x8004021A
The HTTP request failed. The server response was: %1.
0x8004021B
This is a multipart body part. It has no content other than the body parts contained within it.
0x8004021C
Multipart body parts must be encoded as 7bit, 8bit, or binary.
0x8004021E
The requested property was not found.
0x80040220
The "SendUsing" configuration value is invalid.
0x80040221
The "PostUsing" configuration value is invalid.
0x80040222
The pickup directory path is required and was not specified.
0x80040223
One or more messages could not be deleted.
0x80040227
The property is read-only.
0x80040228
The property cannot be deleted.
0x80040229
Data written to the object are inconsistent or invalid.
x8004022A
The requested property is not in the mail header namespace.
0x8004022B
The requested character set is not installed on the computer.
0x8004022C
The ADO stream has not been opened.
0x8004022D
The content properties are missing.
0x8004022E
Content properties XML must be encoded using UTF-8.
0x8004022F
Failed to parse content properties XML.
0x80040230
Failed to convert a property from XML to a requested type.
0x80040231
No directories were specified for resolution.
0x80040232
Failed to resolve against one or more of the specified directories.
0x80040233
Could not find the Sender's mailbox.
0x80040234
Binding to self is not allowed.
0x80044000
The first argument is invalid.
0x80044001
The second argument is invalid.
0x80044002
The third argument is invalid.
0x80044003
The fourth argument is invalid.
0x80044004
The fifth argument is invalid.
0x800CCE05
The requested body part was not found in this message.
0x800CCE1D
The content encoding type is invalid.
Saludos

lunes, 12 de septiembre de 2011

Herramienta de Ingeniería Reversa en Dynamics AX

Navegando por internet encontre información muy interesante acerca de la herramienta de ingeniería reversa que tiene MS Dynamics AX, espero que les guste. :)
--------------------------------------------------------------------------------------------------
Microsoft Dynamics AX dispone de una muy buena herramienta de ingeniería inversa gracias a la cual podemos visualizar un modelo de datos u objetos de la aplicación en UML y ERX.


Generando Modelos y Archivos ERX
La herramienta de ingeniería inversa puede generar un modelo UML de datos u objetos o un archivo .erx para elementos de aplicación desde un proyecto privado o compartido o incluso desde una perspectiva. Si se desea utilizar proyectos privados o compartidos lo primero es crear el proyecto y llevar los elementos, que tu deseas modelar, al proyecto.

Modelo UML de Datos y Objetos
Bien, como ya hemos mencionado la herramienta de ingenería inversa puede crear los siguientes tipos de modelos de datos:
  • Modelo de Datos UML: este modelo nos provee una representación visual de los metadatos de las tablas y de las relaciones y vistas. Este modelo contiene una clase por cada tabla y vista. Esta clase captura los atributos y asociaciones, así como tambien los tipos de datos de los campos, índices, y relaciones. Para crear un modelo de datos UML en Visio debemos seguir los siguientes pasos:
    • En el ciente de Microsoft Dynamics AX, en la barra de menú, seleccionar Herramientas, luego Herramientas de desarrollo y luego hacer clic en Ingeniería inversa. El cuadro de dialogo de Ingeniería inversa se abrirá.
    • Seleccionamos Modelo de datos UML de Visio.
    • Seleccionamos el tipo de ítem desde el que deseamos generar nuestro modelo, estos pueden ser: Proyecto privado, Proyecto compartido, o Perspectiva, y seleccionamos los ítems desde la lista desplegable.
    • Si deseamos cambiar el nombre o la ruta de alojamiento del archivo, hacemos clic en ícono de la carpeta, y especificamos un nombre y una dirección para el archivo.
    • Hacemos clic en OK.
    • Despues de que el modelo de datos es creado, Visio se abrirá y ya contendrá todos los elementos UML con el diagrama en blanco. Usando el explorador de modelo arrastramos los elementos del modelo al diagrama.
  • Modelo de Objetos UML: este modelo nos provee una representación visual de los metadatos de clases, interfaces, vistas, tablas y relaciones. Un modelo de objeto contiene una clase para cada clase, vista, tablas e interfaces para cada interfaz de Microsoft Dynamics AX. Este modelo capatura atributos, así como tambien referencias a tablas y clases, extended data type, base enums, y tipos de datos nativos. El modelo tambien contiene cualquier clase que se extienda de otra clase, clases que son implementadas en las intefaces, y clases que son llamadas por otras. Para crear un modelo de objetos UML en Visio debemos seguir los siguientes pasos:
    • En el cliente de Microsoft Dynamics AX, en la barra de menú, seleccinar Herramientas, luego Herramientas de desarrollo y luego hacer clic en Ingeniería inversa. El cuadro de dialo de Ingeniería inversa se abrirá.
    • Seleccionamos Modelo de Objetos UML de Visio.
    • Seleccionamos el tipo de ítem desde el que deseamos generar nuestro modelo, estos pueden ser: Proyecto privado, Proyecto compartido, o Perspectiva, y seleccionamos los ítems desde la lista desplegable.
    • Si deseamos cambiar el nombre o la ruta de alojamiento del archivo, hacemos clic en ícono de la carpeta, y especificamos un nombre y una dirección para el archivo.
    • Hacemos clic en OK.
    • Despues de que el modelo de objetos es creado, Visio se abrirá y ya contedrná todos los elementos UML con el diagrama en blanco. Usando el explorador de modelo arrastramos los elementos del modelo al diagrama.
En resumen, los siguientes elementos son incluidos en los diagramas UML:
  • Modelo de Datos
    • Tablas
    • Propiedades de los grupos de tablas
    • Campos
    • Campos con información indexada
    • Todos los extended data type
    • Todos los base enums
    • Todos los tipos de datos X++
    • Todas las tablas referenciadas
    • Vistas
    • Campos de vistas
  • Modelo de Objetos
    • Tablas
    • Campos
    • Métodos
    • Parámetros de métodos
    • Clases
    • Todos los extended data type
    • Todos los base enums
    • Todos los tipos de datos X++
    • Todas las referencias a tablas y clases
    • Vistas
    • Campos de vistas
Aqui les dejo un ejemplo para generar en visio un diagrama Entidad Relación, basado en objetos existentes en AX, utilizando el formato ERX de ERwin.
Para facilitar el ejemplo creamos un nuevo proyecto e incluimos algunas tablas con la función Ordenación/filtro avanzados. Se incluira todas las tablas que empiezan por InventDim

Con esto se genera un proyecto razonablemente pequeño.

Ahora vamos a la opción de menú:
Herramientas > Herramientas de desarrollo > Utilizar técnicas de ingeniería inversa
Configuramos un destino para el fichero exportado, elegimos la opción de formato ERX y buscamos el proyecto que acabamos de guardar para decirle al sistema qué objetos debe exportar.

A partir de aquí trabajamos con Microsoft Office Visio, en mi caso con la versión 2007. Vamos a crear un nuevo diagrama de modelo de bases de datos:


Al crear un diagrama de este tipo, visio nos habilita el menú Base de datos > Importar > Importar archivo ERX de ERwin. Buscamos el fichero exportado por AX y Aceptar.
Visio nos incluirá todas las tablas en la ventana Tablas y vistas (Menú Base de datos > Ver > Tablas y vistas). Desde aquí se pueden seleccionar las tablas que se quiera y arrastrarlas directamente al diseño:
Y eso es todo:



Saludos.

sábado, 27 de agosto de 2011

Mover Archivos desde MS Dynamics AX

Hola, mediante este codigo se podra mover archivos desde Dynamics AX, teniendo esto, tambien se puede copiar y eliminar archivos, es cuestion de hacer unos pequeñisimos cambios en la parte del FOR (se los dejo a su investigación :D).

static void MoverArchivos(Args _args)

{
     System.IO.DirectoryInfo di;
     System.Type arrayType;
     System.Array array;
     System.IO.FileInfo fi;
     FilePath filePath, moveFilePath, shortFile;
     FileNameOpen fileNameOpen;
     FileIOPermission dirPermission, filePermission;
     InteropPermission interopPermission;
     Set permissionSet;
     int i;
     int l;
     ;

     interopPermission = new InteropPermission(InteropKind::ClrInterop);
     filePath = '\\\\MSAXPRB\\Prueba\\a\\';
     dirPermission = new FileIOPermission(filePath, 'R');
     permissionSet = new Set(Types::Class);
     permissionSet.add(interopPermission);
     permissionSet.add(dirPermission);
     CodeAccessPermission::assertMultiple(permissionSet);
     di = new System.IO.DirectoryInfo(filePath);
     arrayType = System.Type::GetType("System.IO.FileInfo");
     array = System.Array::CreateInstance(arrayType, 1);
     array = di.GetFiles();
     l = array.get_Length();
     CodeAccessPermission::revertAssert();
     if (l > 0)
    {
          for (i = 0; i < l; i++)
         {
               interopPermission = new InteropPermission(InteropKind::ClrInterop);
               interopPermission.assert();
               fi = array.GetValue(i);
               fileNameOpen = fi.get_FullName();
               CodeAccessPermission::revertAssert();
               filepermission = new FileIOPermission(fileNameOpen, 'W');
               interopPermission = new InteropPermission(InteropKind::ClrInterop);
               permissionSet = new Set(Types::Class);
               permissionSet.add(interopPermission);
               permissionSet.add(dirPermission);
               CodeAccessPermission::assertMultiple(permissionSet);
               shortFile = fi.get_Name();
               moveFilePath = "\\\\MSAXPRB\\Prueba\\b\\" + shortFile;
               fi.MoveTo(moveFilePath);
               CodeAccessPermission::revertAssert();
         }
     }
     box::info("Archivos movidos");
}


Un ejemplo del uso de este codigo podria ser al momento de hacer procesos en batch para importar data de archivos.


Saludos.

viernes, 26 de agosto de 2011

Leer archivos mediante la clase CommaIo

Con esta clase se puede leer archivos externos para poder ingresarlos mediante interface a las tablas de MSDAX.
Este metodo contiene 2 parametros, el primero es donde se pondra la ruta del archivo y el segundo donde pondremos el modo a utilizar, nosotros utilizaremos el modo leer, por lo tanto utilizaremos "R".

CommaIo io;

container con;
FileIoPermission perm;

#define.EjemploArchivo(@"c:\prueba.txt")
#define.EjemploModo("R")
;

perm = new FileIoPermission(#EjemploArchivo, #EjemploModo);

if (perm == null)
{
     info("No existe archivo");
}

// Dando permisos para la ejecución de CommaIo.new method.
perm.assert();

// Cargando archivo.
io = new CommaIo(#ExampleFile, #ExampleOpenMode);
if (io)
{
     con = io.read();
}

// Cerrando los permisos de acceso.
CodeAccessPermission::revertAssert();

-------------------------------------------------------
Teniendo la información en un contenedor, simplemente es cuestión de recorrerlo.
Saludos.

viernes, 22 de julio de 2011

Manipular varios campos al modificar un campo principal de un formulario

Hola, vamos a realizar un caso en que al momento de modificar un campo, se modifiquen otros a consecuencia. Para facilitar el ejemplo los campos seran de tipo enum (NoYes).
Utilizaremos lo siguiente:
TABLA: Table1
     CAMPO: Field1, Field2, Field3
     METODO: Update()
FORMULARIO: Form1
     DATASOURCE: Table1
     DISEÑO: Grid(todos los campos del datasource)
--------------------------------------Pasos---------------------------------------------------
En el metodo update() de la tabla ponemos las condiciones:

public void update()
{
     if(this.Field1 == noyes::Yes)
    {
          this.Field2 = noyes::No;
          this.Field3 = noyes::No;
    }
     if(this.Field2 == noyes::Yes)

    {
          this.Field1 = noyes::No;
          this.Field3 = noyes::No;
    }
     if(this.Field3 == noyes::Yes)
    {
          this.Field1 = noyes::No;
          this.Field2 = noyes::No;
    }
     super();
}

En cada campo del grid del formulario vamos a crear metodos clicked() y poner lo siguiente:

public void clicked()
{
     super();
     Table1_ds.research();
}

Con lo realizado, al momento de que un campo este con check, los otros se van a blanquear.
Saludos.

jueves, 21 de julio de 2011

Manejando columnas y filas de un grid

Hola, hay veces que nos piden capturar especificamente algunas columnas o filas de un grid en un formulario. Daré un ejemplo de cómo hacer dicho procedimiento, utilizando un botón. Para esto pondremos el siguiente código en el metodo clicked() del botón:

void clicked()
{
     int i;
     int numcol, f;
     ;

     numcol = tuGrid.controlCount();
     if (TuDatasource_ds.first())
    {
          do
         {
               for (f=1;f<=numcol;f++)
              {
                   box::info(tuGrid.controlNum(f).valueStr());
              }
          } While (TuDatasource_ds.next());
    }
    super();
}

Nota: es importante tener la propiedad "AutoDeclaration" del grid en TRUE.
Saludos.

martes, 7 de junio de 2011

Controlar desde un formulario hijo a uno padre

Lo que haremos es actualizar un grid que se encuentra en el formulario padre (formulario llamador) desde un formulario hijo (formulario llamado).
Para nuestro ejemplo, vamos a trabajar con el formulario VendInvoiceJournal.
  1. En la tabla VendInvoiceJour creamos el campo PRB_Actualiza (extended: name).
  2. Creamos el botón PRB_Pase en el formulario VendInvoiceJournal (VendInvoiceJournal/Designs/Design/Tab/Overview/OverviewButtonGroup/PRB_Pase).
  3. Creamos la tabla temporal PRB_TablaPase.
  4. Creamos el formulario PRB_PaseActualiza
  5. Creamos el metodo clicked() en el boton PRB_Pase del formulario VendInvoiceJournal.
  6. Agregamos el siguiente código:
    void clicked() { Args args; FormRun formRun; ; super(); args = new Args(formstr(PRB_PaseActualiza)); args.record(vendinvoicejour); formRun = classFactory.formRunClass(args); formRun.init(); formRun.run(); formRun.wait(); vendInvoiceJour_ds.research(); }
  7. Creamos el metodo clicked() en el botón Button del formulario PRB_PaseActualiza
  8. Agreganos el siguiente codigo:
    void clicked()
    { vendinvoicejour vij; vendinvoicejour xxx; super(); vij = element.args().record(); update_recordset xxx setting PRB_Actualiza = DataSource1_PRB_Actualiza.text() where xxx.LedgerVoucher == DataSource1_LedgerVoucher.text(); element.close(); }
  9. Hacemos pruebas:
    a. Abrimos el formulario VendInvoiceJournal (Proveedores/Consultas/Diarios/Facturas) y seleccionamos una linea


    b. Hacemos click en el botón creado “llamada formulario” y nos abre el formulario creado PRB_PaseActualiza

    c. Ponemos data en el campo Actualiza. Ej. Alonso
    d. Presionamos el botón Actualizar. Se cierra el formulario y actualiza el grid del formulario padre. 
Saludos.

domingo, 5 de junio de 2011

Ingresar direccion del proveedor mediante excel desde un JOB

Hola, les dejo como podemos ingresar direcciones de un proveedor en forma masiva desde un job mediante un excel.
  1. El excel debe tener las columnas codigo del proveedor y direccion, con la informacion correspondiente.
Creamos el JOB

static void ActualizaDireccion(Args _args)
{
    container                 conSheets;
    ExcelImportADO      xlImport;
    SysDataExcelCOM   dataExcelCom;
    Filename                  strFlename;
    accountnum             id;
   
str                 direccion;   
    vendtable           vend;   
    dirpartytable      dir;   
   
address             addre;   
    int i = 0;
    ;

    strFilename = "C:\\Users\\PC\\Desktop\\direccion.xls";
    xlImport    = new ExcelImportADO(strFilename);

    try
    {
        // abriendo solo la primera hoja de excel       if(!xlImport.openFile())
            throw error(strfmt("Error opening Excel file «%1»", strFilename));

                while(!xlImport.eof())//previo
                {
                    id              =       xlImport.getFieldValue(1);
                    direccion       =       xlImport.getFieldValue(2);

                    while select vend
                        where vend.AccountNum == id
                    {
                        while select dir
                            where dir.PartyId == vend.PartyId
                        {
                             if(!address::find(2303,dir.RecId,addresstype::None).AddrRecId)
                            {
                                addre.AddrTableId = 2303; //vendtable
                                addre.AddrRecId   = dir.RecId;
                                addre.Street      = direccion;
                                addre.Address     = direccion;
                                addre.insert();
                                i++;
                                   }
                         
}
        }

      xlImport.moveNext();

  }

  xlImport.finalize();

info("direcciones: " + num2str(i,3,2,1,1));

}
catch(Exception::Error)
{
     info("error");
     xlImport.finalize();
}
}

  1. Ejecutar el JOB.
Con esto se podria ver otras funcionalidades como modificacion, eliminacion de direcciones, ademas de hacer pruebas de como hacerlo para clientes (me imagino que es similar).

Saludos.